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 || env.DidThrow) { 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); }
private void ExecuteExecuteStmt(Ast.ExecuteStmt stmt, ScriptEnv env) { var parser = new ScriptParser(_notebook); var runner = new ScriptRunner(_notebook, _scripts); var script = parser.Parse(GetScriptCode(stmt.ScriptName)); var subEnv = new ScriptEnv(); foreach (var arg in stmt.Arguments) { subEnv.Vars[arg.Name.ToLower()] = EvaluateExpr(arg.Value, env); } try { runner.Execute(script, subEnv); } catch (UncaughtErrorScriptException ex) { env.ErrorNumber = ex.ErrorNumber; env.ErrorMessage = ex.ErrorMessage; env.ErrorState = ex.ErrorState; env.DidThrow = true; return; } env.Output.Append(subEnv.Output); var returnCode = subEnv.Output.ScalarResult; if (stmt.ReturnVariableName != null) { var name = stmt.ReturnVariableName.ToLower(); env.Vars[name] = returnCode ?? 0L; } }
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); }
private void ExecuteSqlStmt(Ast.SqlStmt stmt, ScriptEnv env) { foreach (var beforeStmt in stmt.RunBefore) { ExecuteStmt(beforeStmt, env); if (env.DidThrow) { return; } } try { var dt = _notebook.Query(stmt.Sql, env.Vars); if (dt.Columns.Any()) { env.Output.DataTables.Add(dt); } } finally { foreach (var afterStmt in stmt.RunAfter) { ExecuteStmt(afterStmt, env); if (env.DidThrow) { break; } } } }
private ExportTxtStmtRunner(INotebook 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); } }
private void ExecuteImportXlsStmt(Ast.ImportXlsStmt stmt, ScriptEnv env) { try { ImportXlsStmtRunner.Run(_notebook, env, this, stmt); } catch (Exception ex) { Throw(env, ex.Message); } }
private void ExecuteReturnStmt(Ast.ReturnStmt stmt, ScriptEnv env) { if (stmt.Value != null) { env.Output.ScalarResult = EvaluateExpr(stmt.Value, env); } env.DidReturn = true; }
private void Throw(ScriptEnv env, object errorMessage) { env.ErrorMessage = errorMessage; env.DidThrow = true; // make the error message available via the error_message() function _notebook.UserData.LastError.ErrorMessage = env.ErrorMessage; }
private void ExecuteExportTxtStmt(Ast.ExportTxtStmt stmt, ScriptEnv env) { try { ExportTxtStmtRunner.Run(_notebook, env, this, stmt); } catch (Exception ex) { Throw(env, -1, ex.Message, -1); } }
private void ExecuteTryCatchStmt(Ast.TryCatchStmt stmt, ScriptEnv env) { ExecuteBlock(stmt.TryBlock, env); if (env.DidThrow) { env.DidThrow = false; ExecuteBlock(stmt.CatchBlock, env); } }
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); }
private void ExecuteBlock(Ast.Block block, ScriptEnv env) { foreach (var stmt in block.Statements) { ExecuteStmt(stmt, env); if (env.DidReturn || env.DidBreak || env.DidContinue || env.DidThrow) { return; } } }
public string EvaluateIdentifierOrExpr(Ast.IdentifierOrExpr idOrExpr, ScriptEnv env) { if (idOrExpr.Expr != null) { return(EvaluateExpr <string>(idOrExpr.Expr, env)); } else { return(idOrExpr.Identifier); } }
private void ExecuteThrowStmt(Ast.ThrowStmt stmt, ScriptEnv env) { if (stmt.HasErrorValues) { var errorMessage = EvaluateExpr(stmt.Message, env);; Throw(env, errorMessage); } else { env.DidThrow = true; } }
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 || env.DidThrow) { return; } else if (env.DidBreak) { env.DidBreak = false; break; } else if (env.DidContinue) { env.DidContinue = false; } counter += step; } }
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}\"."); } }
private void Throw(ScriptEnv env, object errorNumber, object errorMessage, object errorState) { env.ErrorNumber = errorNumber; env.ErrorMessage = errorMessage; env.ErrorState = errorState; env.DidThrow = true; // make the error number, message, and state available via the error_number(), error_message(), and // error_state() functions. _notebook.UserData.LastError.ErrorNumber = env.ErrorNumber; _notebook.UserData.LastError.ErrorMessage = env.ErrorMessage; _notebook.UserData.LastError.ErrorState = env.ErrorState; }
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); } }
public object EvaluateExpr(Ast.Expr expr, ScriptEnv env) { 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."); } }
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}\"."); } }
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] = 0L; } } }
public void Execute(Ast.Script script, ScriptEnv env) { 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."); } else if (env.DidThrow) { throw new UncaughtErrorScriptException(env.ErrorNumber, env.ErrorMessage, env.ErrorState); } }
private ImportCsvStmtRunner(INotebook notebook, ScriptEnv env, ScriptRunner runner, Ast.ImportCsvStmt stmt) { _notebook = notebook; _env = env; _runner = runner; _stmt = stmt; 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); break; case "HEADER_ROW": _headerRow = _stmt.OptionsList.GetOptionBool(option, _runner, _env, true); 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; case "IF_CONVERSION_FAILS": _ifConversionFails = (IfConversionFails)_stmt.OptionsList.GetOptionLong( option, _runner, _env, 1, minValue: 1, maxValue: 3); break; default: throw new Exception($"\"{option}\" is not a recognized option name."); } } }
private void ExecutePrintStmt(Ast.PrintStmt stmt, ScriptEnv env) { var value = EvaluateExpr(stmt.Value, env); var byteArray = value as byte[]; if (byteArray != null) { if (ArrayUtil.IsSqlArray(byteArray)) { env.Output.TextOutput.Add( "[" + string.Join(", ", ArrayUtil.GetArrayElements(byteArray)) + "]" ); return; } } env.Output.TextOutput.Add(value.ToString()); }
private ImportTxtStmtRunner(INotebook notebook, ScriptEnv env, ScriptRunner runner, Ast.ImportTxtStmt stmt) { _notebook = notebook; _env = env; _runner = runner; _stmt = stmt; _filePath = GetFilePath(); _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); 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."); } } }
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."); } }
public static Encoding GetOptionEncoding(this Ast.OptionsList optionsList, string name, ScriptRunner runner, ScriptEnv env) { var encodingNum = optionsList.GetOptionInt(name, runner, env, 0); if (encodingNum == 0) { return(null); } else if (encodingNum < 0 || encodingNum > 65535) { throw new Exception($"{name} must be between 0 and 65535."); } else { Encoding encoding = null; try { encoding = Encoding.GetEncoding(encodingNum); } catch (ArgumentOutOfRangeException) { // invalid codepage } catch (ArgumentException) { // invalid codepage } catch (NotSupportedException) { // invalid codepage } if (encoding == null) { throw new Exception($"The code page {encodingNum} is invalid or is not supported on this system."); } else { return(encoding); } } }
// must be run from the SQLite thread public static void Run(INotebook notebook, ScriptEnv env, ScriptRunner runner, Ast.ExportTxtStmt stmt) { var exporter = new ExportTxtStmtRunner(notebook, env, runner, stmt); exporter.Export(); }
private ImportXlsStmtRunner(INotebook notebook, ScriptEnv env, ScriptRunner runner, Ast.ImportXlsStmt stmt) { _notebook = notebook; _env = env; _runner = runner; _stmt = stmt; _filePath = _runner.EvaluateExpr <string>(_stmt.FilenameExpr, _env); if (!File.Exists(_filePath)) { throw new Exception($"The specified XLS/XLSX file was not found: \"{_filePath}\""); } if (_stmt.WhichSheetExpr != null) { _whichSheet = _runner.EvaluateExpr(_stmt.WhichSheetExpr, _env); } int?index; foreach (var option in _stmt.OptionsList.GetOptionKeys()) { switch (option) { case "FIRST_ROW": _firstRowIndex = _stmt.OptionsList.GetOptionInt(option, _runner, _env, 1, minValue: 1) - 1; break; case "LAST_ROW": var lastRowNum = _stmt.OptionsList.GetOptionInt(option, _runner, _env, 0, minValue: 0); if (lastRowNum == 0) { _lastRowIndex = null; } else { _lastRowIndex = lastRowNum - 1; } break; case "FIRST_COLUMN": index = XlsUtil.ColumnRefToIndex(_stmt.OptionsList.GetOption <object>(option, _runner, _env, null)); if (index.HasValue) { _firstColumnIndex = index.Value; } else { throw new Exception($"The {option} option must be a valid column number or string."); } break; case "LAST_COLUMN": var lastColumnValue = _stmt.OptionsList.GetOption <object>(option, _runner, _env, null); if (lastColumnValue.Equals(0)) { _lastColumnIndex = null; break; } index = XlsUtil.ColumnRefToIndex(lastColumnValue); if (index.HasValue) { _lastColumnIndex = index.Value; } else { throw new Exception($"The {option} option must be a valid column number or string."); } break; case "HEADER_ROW": _headerRow = _stmt.OptionsList.GetOptionBool(option, _runner, _env, true); 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 "IF_CONVERSION_FAILS": _ifConversionFails = (IfConversionFails)_stmt.OptionsList.GetOptionLong( option, _runner, _env, 1, minValue: 1, maxValue: 3); break; default: throw new Exception($"\"{option}\" is not a recognized option name."); } } }