Skip to content

Commit 5b90947

Browse files
authored
Merge pull request #36 from smeup/SETLL
Setll
2 parents cf17dff + 7aa2685 commit 5b90947

File tree

16 files changed

+138
-57
lines changed

16 files changed

+138
-57
lines changed

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/db/sql/DBSQLFile.kt

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ import com.smeup.rpgparser.interpreter.DBFile
44
import com.smeup.rpgparser.interpreter.RecordField
55
import com.smeup.rpgparser.interpreter.Record
66
import com.smeup.rpgparser.interpreter.Value
7+
import com.smeup.rpgparser.utils.Comparison
78
import java.sql.Connection
89
import java.sql.ResultSet
910

1011
class DBSQLFile(private val name: String, private val connection: Connection) : DBFile {
1112
private var resultSet: ResultSet? = null
1213
private var lastKey: List<RecordField> = emptyList()
1314

14-
private val keys: List<String> by lazy {
15+
private val thisFileKeys: List<String> by lazy {
1516
val indexes = connection.primaryKeys(name)
1617
if (indexes.isEmpty()) connection.orderingFields(name) else indexes
1718
}
@@ -60,18 +61,19 @@ class DBSQLFile(private val name: String, private val connection: Connection) :
6061

6162
override fun eof(): Boolean = resultSet?.isLast ?: false
6263

63-
override fun chain(key: Value): Record {
64-
return chain(toFields(key))
65-
}
64+
override fun chain(key: Value): Record = chain(toFields(key))
65+
66+
override fun setll(key: Value) = setll(toFields(key))
6667

6768
private fun toFields(keyValue: Value): List<RecordField> {
68-
val keyName = keys.first()
69+
val keyName = thisFileKeys.first()
6970
return listOf(RecordField(keyName, keyValue))
7071
}
7172

7273
override fun chain(keys: List<RecordField>): Record {
7374
val keyNames = keys.map { it.name }
74-
val sql = "SELECT * FROM $name ${keyNames.whereSQL()} ${keyNames.orderBySQL()}"
75+
// TODO Using thisFileKeys: TESTS NEEDED!!!
76+
val sql = "SELECT * FROM $name ${keyNames.whereSQL()} ${thisFileKeys.orderBySQL()}"
7577
val values = keys.map { it.value }
7678
resultSet.closeIfOpen()
7779
connection.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE).use {
@@ -80,4 +82,16 @@ class DBSQLFile(private val name: String, private val connection: Connection) :
8082
}
8183
return resultSet.toValues()
8284
}
83-
}
85+
86+
override fun setll(keys: List<RecordField>) {
87+
val keyNames = keys.map { it.name }
88+
// TODO Using thisFileKeys: TESTS NEEDED!!!
89+
val sql = "SELECT * FROM $name ${keyNames.whereSQL(Comparison.GE)} ${thisFileKeys.orderBySQL()}"
90+
val values = keys.map { it.value }
91+
resultSet.closeIfOpen()
92+
connection.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE).use {
93+
it.bind(values)
94+
resultSet = it.executeQuery()
95+
}
96+
}
97+
}

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/db/sql/SQLUtils.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.smeup.rpgparser.db.sql
22

33
import com.smeup.rpgparser.interpreter.*
4+
import com.smeup.rpgparser.utils.Comparison
45

56
fun FileMetadata.toSQL(): List<String> =
67
listOf(
@@ -21,16 +22,16 @@ fun String.insertSQL(values: List<Pair<String, Value>>): String {
2122
return "INSERT INTO $this ($names) VALUES($questionMarks)"
2223
}
2324

24-
fun List<String>.whereSQL(): String =
25+
fun List<String>.whereSQL(comparation: Comparison = Comparison.EQ): String =
2526
if (this.isEmpty()) {
2627
""
2728
} else {
28-
"WHERE " + this.joinToString(" AND ") { "$it = ?" }
29+
"WHERE " + this.joinToString(" AND ") { "$it ${comparation.symbol} ?" }
2930
}
3031

3132
fun List<String>.orderBySQL(): String =
3233
if (this.isEmpty()) {
3334
""
3435
} else {
3536
"ORDER BY " + this.joinToString()
36-
}
37+
}

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/internal_interpreter.kt

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package com.smeup.rpgparser.interpreter
22

33
import com.smeup.rpgparser.parsing.ast.*
44
import com.smeup.rpgparser.parsing.ast.AssignmentOperator.*
5-
import com.smeup.rpgparser.parsing.ast.Comparison.*
5+
import com.smeup.rpgparser.utils.Comparison.*
66
import com.smeup.rpgparser.parsing.parsetreetoast.LogicalCondition
77
import com.smeup.rpgparser.parsing.parsetreetoast.MuteAnnotationExecutionLogEntry
88
import com.smeup.rpgparser.utils.*
@@ -702,42 +702,30 @@ class InternalInterpreter(val systemInterface: SystemInterface) : InterpreterCor
702702
}
703703
}
704704
is ChainStmt -> {
705-
val dbFile = dbFileMap[statement.name]
706-
require(dbFile != null) {
707-
"Line: ${statement.position.line()} - File definition ${statement.name} not found"
708-
}
709-
lastDBFile = dbFile
705+
val dbFile = dbFile(statement.name, statement)
710706
val record = if (statement.searchArg.type() is KListType) {
711707
dbFile.chain(toSearchValues(statement.searchArg))
712708
} else {
713709
dbFile.chain(eval(statement.searchArg))
714710
}
715-
if (!record.isEmpty()) {
716-
lastFound = true
717-
record.forEach { assign(dataDefinitionByName(it.key)!!, it.value) }
711+
fillDataFrom(record)
712+
}
713+
is SetllStmt -> {
714+
val dbFile = dbFile(statement.name, statement)
715+
if (statement.searchArg.type() is KListType) {
716+
dbFile.setll(toSearchValues(statement.searchArg))
718717
} else {
719-
lastFound = false
718+
dbFile.setll(eval(statement.searchArg))
720719
}
721720
}
722721
is ReadEqualStmt -> {
723-
val dbFile = dbFileMap[statement.name]
724-
require(dbFile != null) {
725-
"Line: ${statement.position.line()} - File definition ${statement.name} not found"
726-
}
727-
lastDBFile = dbFile
728-
val record = if (statement.searchArg == null) {
729-
dbFile.readEqual()
730-
} else if (statement.searchArg.type() is KListType) {
731-
dbFile.readEqual(toSearchValues(statement.searchArg))
732-
} else {
733-
dbFile.readEqual(eval(statement.searchArg))
734-
}
735-
if (!record.isEmpty()) {
736-
lastFound = true
737-
record.forEach { assign(dataDefinitionByName(it.key)!!, it.value) }
738-
} else {
739-
lastFound = false
722+
val dbFile = dbFile(statement.name, statement)
723+
val record = when {
724+
statement.searchArg == null -> dbFile.readEqual()
725+
statement.searchArg.type() is KListType -> dbFile.readEqual(toSearchValues(statement.searchArg))
726+
else -> dbFile.readEqual(eval(statement.searchArg))
740727
}
728+
fillDataFrom(record)
741729
}
742730
else -> TODO(statement.toString())
743731
}
@@ -747,11 +735,27 @@ class InternalInterpreter(val systemInterface: SystemInterface) : InterpreterCor
747735
throw e
748736
} catch (e: RuntimeException) {
749737
throw RuntimeException("Issue executing statement $statement -> $e", e)
750-
} catch (e: NotImplementedError) {
751-
throw RuntimeException("Issue executing statement $statement -> $e", e)
752738
}
753739
}
754740

741+
private fun fillDataFrom(record: Record) {
742+
if (!record.isEmpty()) {
743+
lastFound = true
744+
record.forEach { assign(dataDefinitionByName(it.key)!!, it.value) }
745+
} else {
746+
lastFound = false
747+
}
748+
}
749+
750+
private fun dbFile(name: String, statement: Statement): DBFile {
751+
val dbFile = dbFileMap[name]
752+
require(dbFile != null) {
753+
"Line: ${statement.position.line()} - File definition $name not found"
754+
}
755+
lastDBFile = dbFile
756+
return dbFile
757+
}
758+
755759
private fun toSearchValues(searchArgExpression: Expression): List<RecordField> {
756760
val kListName = searchArgExpression.render().toUpperCase()
757761
val parms = klists[kListName]

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/logs.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.smeup.rpgparser.interpreter
22

33
import com.smeup.rpgparser.parsing.ast.*
4+
import com.smeup.rpgparser.utils.asNonNullString
45
import com.strumenta.kolasu.model.Node
56
import com.strumenta.kolasu.model.Position
67
import java.io.PrintStream
@@ -548,6 +549,7 @@ fun List<InterpreterLogHandler>.log(logEntry: LogEntry) {
548549
}
549550
}
550551

551-
fun Position?.line() = this?.start?.line?.toString() ?: ""
552-
fun Node?.startLine() = this?.position?.start?.line?.toString() ?: ""
553-
fun Node?.endLine() = this?.position?.end?.line?.toString() ?: ""
552+
fun Position?.line() = this?.start?.line.asNonNullString()
553+
fun Position?.atLine() = this?.start?.line?.let { "line $it " } ?: ""
554+
fun Node?.startLine() = this?.position?.start?.line.asNonNullString()
555+
fun Node?.endLine() = this?.position?.end?.line.asNonNullString()

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/interpreter/system_interface.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ class Record(vararg fields: RecordField) : LinkedHashMap<String, Value>() {
6060
interface DBFile {
6161
fun chain(key: Value): Record
6262
fun chain(keys: List<RecordField>): Record
63+
fun setll(key: Value)
64+
fun setll(keys: List<RecordField>)
6365
fun readEqual(): Record
6466
fun readEqual(key: Value): Record
6567
fun readEqual(keys: List<RecordField>): Record

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/Comparison.kt

Lines changed: 0 additions & 10 deletions
This file was deleted.

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/mute.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.smeup.rpgparser.parsing.ast
22

33
import com.smeup.rpgparser.interpreter.BooleanValue
44
import com.smeup.rpgparser.interpreter.Value
5+
import com.smeup.rpgparser.utils.Comparison
56
import com.strumenta.kolasu.model.Node
67
import com.strumenta.kolasu.model.Position
78

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/ast/statements.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,13 @@ data class ReadEqualStmt(
130130
) :
131131
Statement(position)
132132

133+
data class SetllStmt(
134+
val searchArg: Expression, // Factor1
135+
val name: String, // Factor 2
136+
override val position: Position? = null
137+
) :
138+
Statement(position)
139+
133140
data class CheckStmt(
134141
val comparatorString: Expression, // Factor1
135142
val baseString: Expression,

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/parsetreetoast/bif.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package com.smeup.rpgparser.parsing.parsetreetoast
22

33
import com.smeup.rpgparser.RpgParser
4-
import com.smeup.rpgparser.interpreter.line
4+
import com.smeup.rpgparser.interpreter.atLine
55
import com.smeup.rpgparser.parsing.ast.*
66
import com.smeup.rpgparser.utils.enrichPossibleExceptionWith
77
import com.strumenta.kolasu.mapping.toPosition
88

99
internal fun RpgParser.BifContext.toAst(conf: ToAstConfiguration = ToAstConfiguration()): Expression {
1010
val position = toPosition(conf.considerPosition)
11-
return enrichPossibleExceptionWith("Error at line ${position?.line()} - ${this.text}") {
11+
return enrichPossibleExceptionWith("${position.atLine()}${this.text}") {
1212
when {
1313
this.bif_elem() != null -> NumberOfElementsExpr(
1414
this.bif_elem().expression().toAst(conf),

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/parsetreetoast/misc.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ internal fun Cspec_fixed_standardContext.toAst(conf: ToAstConfiguration = ToAstC
213213
this.csCHAIN() != null -> this.csCHAIN().toAst(conf)
214214
this.csCHECK() != null -> this.csCHECK().toAst(conf)
215215
this.csKLIST() != null -> this.csKLIST().toAst(conf)
216+
this.csSETLL() != null -> this.csSETLL().toAst(conf)
216217
this.csREADE() != null -> this.csREADE().toAst(conf)
217218
this.csCOMP() != null -> this.csCOMP().toAst(conf)
218219
this.csMULT() != null -> this.csMULT().toAst(conf)
@@ -293,7 +294,7 @@ private fun handleParsingOfTargets(code: String, position: Position?): Assignabl
293294
val containerCode = parts.dropLast(1).joinToString(separator = ".")
294295
QualifiedAccessExpr(
295296
container = handleParsingOfTargets(containerCode, position),
296-
field = ReferenceByName(parts.last()!!),
297+
field = ReferenceByName(parts.last()),
297298
position = position)
298299
}
299300
}
@@ -417,6 +418,16 @@ internal fun CsREADEContext.toAst(conf: ToAstConfiguration): Statement {
417418
toPosition(conf.considerPosition))
418419
}
419420

421+
internal fun CsSETLLContext.toAst(conf: ToAstConfiguration): Statement {
422+
// TODO implement indicators handling
423+
val factor1 = this.factor1Context()?.content?.toAst(conf) ?: throw UnsupportedOperationException("SETLL operation requires factor 1: ${this.text}")
424+
val factor2 = this.cspec_fixed_standard_parts().factor2.text ?: throw UnsupportedOperationException("READE operation requires factor 2: ${this.text}")
425+
return SetllStmt(
426+
factor1,
427+
factor2,
428+
toPosition(conf.considerPosition))
429+
}
430+
420431
internal fun CsCHECKContext.toAst(conf: ToAstConfiguration): Statement {
421432
val position = toPosition(conf.considerPosition)
422433
val factor1 = this.factor1Context()?.content?.toAst(conf) ?: throw UnsupportedOperationException("CHECK operation requires factor 1: ${this.text}")

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/parsetreetoast/mute.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import com.smeup.rpgparser.interpreter.Value
77
import com.smeup.rpgparser.parsing.ast.*
88
import com.smeup.rpgparser.parsing.facade.MutesImmutableMap
99
import com.smeup.rpgparser.parsing.facade.RpgParserFacade
10+
import com.smeup.rpgparser.utils.Comparison
1011
import com.smeup.rpgparser.utils.asLong
1112
import com.strumenta.kolasu.model.Position
1213
import org.antlr.v4.runtime.Token
1314
import org.apache.commons.io.input.BOMInputStream
14-
import java.util.*
1515

1616
data class MuteAnnotationExecutionLogEntry(override val programName: String, val annotation: MuteAnnotation, var result: Value) : LogEntry(programName) {
1717
override fun toString(): String {

rpgJavaInterpreter-core/src/main/kotlin/com/smeup/rpgparser/parsing/parsetreetoast/statements.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.smeup.rpgparser.parsing.parsetreetoast
22

33
import com.smeup.rpgparser.RpgParser
44
import com.smeup.rpgparser.parsing.ast.*
5+
import com.smeup.rpgparser.utils.Comparison
56
import com.smeup.rpgparser.utils.enrichPossibleExceptionWith
67
import com.strumenta.kolasu.mapping.toPosition
78
import com.strumenta.kolasu.model.Position
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.smeup.rpgparser.utils
2+
3+
enum class Comparison(val symbol: String) {
4+
EQ("="),
5+
NE("<>"),
6+
GT(">"),
7+
GE(">="),
8+
LT("<"),
9+
LE("<=");
10+
}

rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/db/sql/integration/ReadEqualDBTest.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class ReadEqualDBTest {
5151

5252
@Test
5353
@Ignore
54-
// At the moment this test fails because it find all the records with key A000, and not just the first 4
54+
// At the moment this test fails because it finds all the records with key A000, and not just the first 4
5555
fun findsExistingRecordsIfReadWithKeyStartingFromFirstKey() {
5656
assertEquals(
5757
listOf("CHRISTINE HAAS", "VINCENZO LUCCHESSI", "DIAN HEMMINGER", "GREG ORLANDO"),
@@ -63,6 +63,18 @@ class ReadEqualDBTest {
6363
)
6464
}
6565

66+
@Test
67+
fun setllReadeFindExistingRecord() {
68+
assertEquals(
69+
listOf("CHRISTINE HAAS", "VINCENZO LUCCHESSI", "SEAN O'CONNELL", "DIAN HEMMINGER", "GREG ORLANDO"),
70+
outputOfDBPgm(
71+
"db/SETLLOK01",
72+
listOf(createEMPLOYEE(), createXEMP2(), createXEMP2Index(), insertRecords()),
73+
mapOf("toFind" to StringValue("A00"))
74+
)
75+
)
76+
}
77+
6678
@Test
6779
fun findsAtLeastExistingRecordsIfReadWithKeyStartingFromFirstKey() {
6880
assertTrue(

rpgJavaInterpreter-core/src/test/kotlin/com/smeup/rpgparser/testing_utils.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,8 @@ class ExtendedCollectorSystemInterface() : CollectorSystemInterface() {
337337
}
338338

339339
open class MockDBFile : DBFile {
340+
override fun setll(key: Value) = TODO()
341+
override fun setll(keys: List<RecordField>) = TODO()
340342
override fun chain(key: Value): Record = TODO()
341343
override fun chain(keys: List<RecordField>): Record = TODO()
342344
override fun readEqual(): Record = TODO()
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
* Sample tables created with
2+
* CALL QSYS.CREATE_SQL_SAMPLE ('SAMPLE')
3+
* See:
4+
* https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/sqlp/rbafysamptblx.htm
5+
* We use here the EMPLOYEE Table:
6+
* https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/sqlp/rbafyemployee.htm
7+
* ------------------------------------------------------------------
8+
FXEMP2 if e k disk
9+
D toFind S 3
10+
D msg S 52 inz(*blanks)
11+
*
12+
C *entry plist
13+
C parm toFind
14+
*-------------------------------------------------------------------------
15+
C toFind Setll XEMP2
16+
C dow not %eof
17+
C toFind reade XEMP2
18+
C IF not %eof
19+
C eval msg = %trim(FIRSTNME) + ' ' + %trim(LASTNAME)
20+
C msg dsply
21+
C endif
22+
C enddo
23+
* Closing resources.
24+
C seton lr

0 commit comments

Comments
 (0)