Skip to content

Commit

Permalink
[cli] Add permissive mode evaluation option to CLI/REPL (#545)
Browse files Browse the repository at this point in the history
  • Loading branch information
alancai98 authored Mar 8, 2022
1 parent 3febaee commit 024892f
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 10 deletions.
11 changes: 11 additions & 0 deletions cli/src/org/partiql/cli/Repl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.partiql.lang.eval.ExprValue
import org.partiql.lang.eval.ExprValueFactory
import org.partiql.lang.eval.MapBindings
import org.partiql.lang.eval.StructOrdering
import org.partiql.lang.eval.TypingMode
import org.partiql.lang.eval.delegate
import org.partiql.lang.syntax.Parser
import org.partiql.lang.util.ConfigurableExprValueFormatter
Expand Down Expand Up @@ -203,6 +204,15 @@ internal class Repl(
outputWriter.write("\n")
}

private fun printTypingMode() {
val typingModeString = when (compiler.compileOptions.typingMode) {
TypingMode.LEGACY -> "LEGACY"
TypingMode.PERMISSIVE -> "PERMISSIVE"
}
outputWriter.write("Typing mode: $typingModeString")
outputWriter.write("\n")
}

fun retrievePartiQLVersionAndHash(): String {
val properties = Properties()
properties.load(this.javaClass.getResourceAsStream("/partiql.properties"))
Expand Down Expand Up @@ -286,6 +296,7 @@ internal class Repl(
state = when (state) {
ReplState.INIT -> {
printWelcomeMessage()
printTypingMode()
printVersionNumber()
ReplState.READY
}
Expand Down
33 changes: 25 additions & 8 deletions cli/src/org/partiql/cli/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ import org.partiql.cli.functions.ReadFile
import org.partiql.cli.functions.WriteFile
import org.partiql.lang.CompilerPipeline
import org.partiql.lang.eval.Bindings
import org.partiql.lang.eval.CompileOptions
import org.partiql.lang.eval.EvaluationSession
import org.partiql.lang.eval.ExprValue
import org.partiql.lang.eval.ExprValueFactory
import org.partiql.lang.eval.TypingMode
import org.partiql.lang.syntax.SqlParser
import java.io.File
import java.io.FileInputStream
Expand All @@ -40,10 +42,6 @@ private val ion = IonSystemBuilder.standard().build()
private val valueFactory = ExprValueFactory.standard(ion)

private val parser = SqlParser(ion)
private val compilerPipeline = CompilerPipeline.build(ion) {
addFunction(ReadFile(valueFactory))
addFunction(WriteFile(valueFactory))
}

private val optParser = OptionParser()

Expand Down Expand Up @@ -84,6 +82,8 @@ private val queryOpt = optParser.acceptsAll(listOf("query", "q"), "PartiQL query
.withRequiredArg()
.ofType(String::class.java)

private val permissiveModeOpt = optParser.acceptsAll(listOf("permissive", "p"), "runs the query in permissive mode")

private val environmentOpt = optParser.acceptsAll(listOf("environment", "e"), "initial global environment (optional)")
.withRequiredArg()
.ofType(File::class.java)
Expand Down Expand Up @@ -114,6 +114,8 @@ private val outputFormatOpt = optParser.acceptsAll(listOf("output-format", "of")
*
* Options:
* * -e --environment: takes an environment file to load as the initial global environment
* * -p --permissive: run the query in permissive typing mode (returns MISSING rather than error for data type
* mismatches)
* * Non interactive only:
* * -q --query: PartiQL query
* * -i --input: input file, default STDIN
Expand All @@ -133,6 +135,21 @@ fun main(args: Array<String>) = try {
throw IllegalArgumentException("Non option arguments are not allowed!")
}

// compile options
// TODO: add other compile options https://github.com/partiql/partiql-lang-kotlin/issues/544
val compileOptions = CompileOptions.build {
when (optionSet.has(permissiveModeOpt)) {
true -> typingMode(TypingMode.PERMISSIVE)
false -> typingMode(TypingMode.LEGACY)
}
}

val compilerPipeline = CompilerPipeline.build(ion) {
addFunction(ReadFile(valueFactory))
addFunction(WriteFile(valueFactory))
compileOptions(compileOptions)
}

// common options
val environment = when {
optionSet.has(environmentOpt) -> {
Expand All @@ -144,9 +161,9 @@ fun main(args: Array<String>) = try {
}

if (optionSet.has(queryOpt)) {
runCli(environment, optionSet)
runCli(environment, optionSet, compilerPipeline)
} else {
runRepl(environment)
runRepl(environment, compilerPipeline)
}
} catch (e: OptionException) {
System.err.println("${e.message}\n")
Expand All @@ -157,11 +174,11 @@ fun main(args: Array<String>) = try {
exitProcess(1)
}

private fun runRepl(environment: Bindings<ExprValue>) {
private fun runRepl(environment: Bindings<ExprValue>, compilerPipeline: CompilerPipeline) {
Repl(valueFactory, System.`in`, System.out, parser, compilerPipeline, environment).run()
}

private fun runCli(environment: Bindings<ExprValue>, optionSet: OptionSet) {
private fun runCli(environment: Bindings<ExprValue>, optionSet: OptionSet, compilerPipeline: CompilerPipeline) {
val input = if (optionSet.has(inputFileOpt)) {
FileInputStream(optionSet.valueOf(inputFileOpt))
} else {
Expand Down
18 changes: 16 additions & 2 deletions cli/test/org/partiql/cli/CliTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import org.partiql.lang.eval.Bindings
import org.partiql.lang.eval.EvaluationException
import org.partiql.lang.eval.ExprValue
import org.partiql.lang.eval.ExprValueFactory
import org.partiql.lang.eval.TypingMode
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
Expand All @@ -34,7 +35,6 @@ class CliTest {
private val ion = IonSystemBuilder.standard().build()
private val valueFactory = ExprValueFactory.standard(ion)
private val output = ByteArrayOutputStream()
private val compilerPipeline = CompilerPipeline.standard(ion)
private val testFile = File("test.ion")

@Before
Expand All @@ -52,7 +52,8 @@ class CliTest {
input: String? = null,
bindings: Bindings<ExprValue> = Bindings.empty(),
outputFormat: OutputFormat = OutputFormat.ION_TEXT,
output: OutputStream = this.output
output: OutputStream = this.output,
compilerPipeline: CompilerPipeline = CompilerPipeline.standard(ion)
) =
Cli(
valueFactory,
Expand Down Expand Up @@ -166,4 +167,17 @@ class CliTest {
fun withoutInputWithInputDataBindingThrowsException() {
makeCli("SELECT * FROM input_data").runAndOutput()
}

@Test
fun runQueryInPermissiveMode() {
val permissiveModeCP = CompilerPipeline.build(ion) {
compileOptions {
typingMode(TypingMode.PERMISSIVE)
}
}
val subject = makeCli("1 + 'foo'", compilerPipeline = permissiveModeCP)
val actual = subject.runAndOutput()

assertAsIon("\$partiql_missing::null", actual)
}
}
24 changes: 24 additions & 0 deletions docs/user/CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Option Description
-o, --output <File> output file, requires the query option (default: stdout)
--of, --output-format <OutputFormat: output format, requires the query option (default: PARTIQL)
(ION_TEXT|ION_BINARY|PARTIQL|PARTIQL_PRETTY)>
-p, --permissive run the PartiQL query in PERMISSIVE typing mode
-q, --query <String> PartiQL query, triggers non interactive mode
```

Expand Down Expand Up @@ -673,3 +674,26 @@ All the available options for customized CSV files are shown as following:
5. Set escape sign (single character only): `'escape':'\'`
6. Set quote sign (single character only): `'quote':'"'`
7. Set delimiter sign (single character only): `'delimiter':','`

## Permissive Typing Mode
By default, the CLI/REPL runs in [LEGACY](https://github.com/partiql/partiql-lang-kotlin/blob/main/lang/src/org/partiql/lang/eval/CompileOptions.kt#L53-L62)
typing mode, which will give an evaluation time error in the case of data type mismatches.

```
(Running in the default LEGACY typing mode)
PartiQL> 1 + 'foo';
org.partiql.lang.eval.EvaluationException: ...
...
```

Specifying the `-p` or `-permissive` flag will allow you to run PartiQL queries in [PERMISSIVE](https://github.com/partiql/partiql-lang-kotlin/blob/main/lang/src/org/partiql/lang/eval/CompileOptions.kt#L64-L73)
typing mode, which will return `MISSING` in the case of data type mismatches.

```
(Running in PERMISSIVE typing mode)
PartiQL> 1 + 'foo';
==='
MISSING
---
OK!
```

0 comments on commit 024892f

Please sign in to comment.