Execution Directives
Execution Directives are CPGQL Directives which execute the traversals they suffix and return the result in a specific format. The most straightforward Execution Directive is toList
which, as the name suggests, executes the CPGQL Query it suffixes and returns the results in a list:
toList
ocular> cpg.call.name.toList
res0: List[String] = List(
"exit",
"printf",
"exit",
"fprintf",
"<operator>.indirectIndexAccess",
"strcmp",
"<operator>.equals",
"<operator>.greaterThan",
"<operator>.logicalAnd"
)
l
toList
has a shorthand named l
:
ocular> cpg.call.name.l
res0: List[String] = List(
"exit",
"printf",
"exit",
"fprintf",
"<operator>.indirectIndexAccess",
"strcmp",
"<operator>.equals",
"<operator>.greaterThan",
"<operator>.logicalAnd"
)
head
Executes the traversal and returns the first result
ocular> cpg.call.name.head
res0: List[String] = List(
"exit",
)
size
size
executes the traversal and returns the size of the result set
ocular> cpg.call.size
res0: Int = 9
Execution Directives and the Ocular Interpreter
Execution Directives sit at the border between CPQGL Queries and the Ocular Interpreter, that is at the border between querying Code Property Graphs, and using the results of those queries for further processing using the Scala programming language. For example, say you'd like to take the results of a query execution and write them to a text file:
// first import the namespace for Java I/O
ocular> import java.io._
import java.io._
// afterwards open a file stream to a new file named `my-query-result.txt`
ocular> val pw = new PrintWriter(new File("./my-query-result.txt" ))
pw: PrintWriter = java.io.PrintWriter@fe4c8fc
// execute your query and store the results in a constant
ocular> val myQueryResult = cpg.call.size
myQueryResult: Int = 9
// cast myQueryResult to a string, and write it to the file stream
ocular> pw.write(myQueryResult.toString())
// close the file streasm
ocular> pw.close()
You'll see your results written to a file, ready for post-analysis:
cat my-query-result.txt
9
Writing the results of a query to a file can also be done in a more concise way using the |>
operator provided by the Ocular Interpreter:
ocular> cpg.call.size.toString() |> "my-query-result.txt"
p
p
executes the traversal and pretty-prints the results:
ocular> cpg.call.p
res26: List[String] = List(
"(CALL,31): ARGUMENT_INDEX: 3, CODE: exit(0), COLUMN_NUMBER: 2, DISPATCH_TYPE: STATIC_DISPATCH, LINE_NUMBER: 11, METHOD_FULL_NAME: exit, NAME: exit, ORDER: 3, SIGNATURE: TODO assignment signature, TYPE_FULL_NAME: ANY",
"(CALL,29): ARGUMENT_INDEX: 2, CODE: printf(\"What is the meaning of life?\\n\"), COLUMN_NUMBER: 2, DISPATCH_TYPE: STATIC_DISPATCH, LINE_NUMBER: 10, METHOD_FULL_NAME: printf, NAME: printf, ORDER: 2, SIGNATURE: TODO assignment signature, TYPE_FULL_NAME: ANY",
"(CALL,27): ARGUMENT_INDEX: 2, CODE: exit(42), COLUMN_NUMBER: 4, DISPATCH_TYPE: STATIC_DISPATCH, LINE_NUMBER: 8, METHOD_FULL_NAME: exit, NAME: exit, ORDER: 2, SIGNATURE: TODO assignment signature, TYPE_FULL_NAME: ANY",
"(CALL,24): ARGUMENT_INDEX: 1, CODE: fprintf(stderr, \"It depends!\\n\"), COLUMN_NUMBER: 4, DISPATCH_TYPE: STATIC_DISPATCH, LINE_NUMBER: 7, METHOD_FULL_NAME: fprintf, NAME: fprintf, ORDER: 1, SIGNATURE: TODO assignment signature, TYPE_FULL_NAME: ANY",
"(CALL,18): ARGUMENT_INDEX: 1, CODE: argv[1], COLUMN_NUMBER: 25, DISPATCH_TYPE: STATIC_DISPATCH, LINE_NUMBER: 6, METHOD_FULL_NAME: <operator>.indirectIndexAccess, NAME: <operator>.indirectIndexAccess, ORDER: 1, SIGNATURE: TODO assignment signature, TYPE_FULL_NAME: ANY",
"(CALL,17): ARGUMENT_INDEX: 1, CODE: strcmp(argv[1], \"42\"), COLUMN_NUMBER: 18, DISPATCH_TYPE: STATIC_DISPATCH, LINE_NUMBER: 6, METHOD_FULL_NAME: strcmp, NAME: strcmp, ORDER: 1, SIGNATURE: TODO assignment signature, TYPE_FULL_NAME: ANY",
"(CALL,16): ARGUMENT_INDEX: 2, CODE: strcmp(argv[1], \"42\") == 0, COLUMN_NUMBER: 18, DISPATCH_TYPE: STATIC_DISPATCH, LINE_NUMBER: 6, METHOD_FULL_NAME: <operator>.equals, NAME: <operator>.equals, ORDER: 2, SIGNATURE: TODO assignment signature, TYPE_FULL_NAME: ANY",
"(CALL,13): ARGUMENT_INDEX: 1, CODE: argc > 1, COLUMN_NUMBER: 6, DISPATCH_TYPE: STATIC_DISPATCH, LINE_NUMBER: 6, METHOD_FULL_NAME: <operator>.greaterThan, NAME: <operator>.greaterThan, ORDER: 1, SIGNATURE: TODO assignment signature, TYPE_FULL_NAME: ANY",
"(CALL,12): ARGUMENT_INDEX: 1, CODE: argc > 1 && strcmp(argv[1], \"42\") == 0, COLUMN_NUMBER: 6, DISPATCH_TYPE: STATIC_DISPATCH, LINE_NUMBER: 6, METHOD_FULL_NAME: <operator>.logicalAnd, NAME: <operator>.logicalAnd, ORDER: 1, SIGNATURE: TODO assignment signature, TYPE_FULL_NAME: ANY"
)
toJson
toJson
executes the traversal and returns the results in a JSON string:
ocular> cpg.call.name.toJson
res28: String = "[\"exit\",\"printf\",\"exit\",\"fprintf\",\"<operator>.indirectIndexAccess\",\"strcmp\",\"<operator>.equals\",\"<operator>.greaterThan\",\"<operator>.logicalAnd\"]"
toJsonPretty
toJsonPretty
executes the traversal and returns the results in a pretty-printed JSON string:
ocular> cpg.call.name.toJsonPretty
res29: String = """[
"exit",
"printf",
"exit",
"fprintf",
"<operator>.indirectIndexAccess",
"strcmp",
"<operator>.equals",
"<operator>.greaterThan",
"<operator>.logicalAnd"
]"""
size
size
executes the traversal and returns the number of results:
ocular> cpg.call.size
res0: Int = 9