annotate src/main/kotlin/name/blackcap/passman/Database.kt @ 24:2188b2f13326

Make some minor tweaks to the help system.
author David Barts <n5jrn@me.com>
date Wed, 03 Jul 2024 17:14:22 -0700
parents ea65ab890f66
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
1 package name.blackcap.passman
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
2
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
3 import java.nio.file.Files
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
4 import java.nio.file.Path
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
5 import java.security.GeneralSecurityException
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
6 import java.security.SecureRandom
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
7 import java.sql.*
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
8
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
9 class Database private constructor(val connection: Connection, val encryption: Encryption){
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
10
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
11 companion object {
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
12 private const val PLAINTEXT = "This is a test."
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
13 private const val SALT_LENGTH = 16
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
14 private const val DEFAULT_PROMPT = "Decryption key: "
21
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 19
diff changeset
15 lateinit var default: Database
0
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
16
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
17 fun open(passwordPrompt: String = DEFAULT_PROMPT, fileName: String = DB_FILE,
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
18 create: Boolean = true): Database {
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
19 val exists = Files.exists(Path.of(fileName))
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
20 if (!exists) {
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
21 if (create) {
5
ad997df1f560 Fix see() to be about as good as sccc.
David Barts <n5jrn@me.com>
parents: 3
diff changeset
22 error("initializing database ${see(fileName)}")
0
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
23 } else {
21
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 19
diff changeset
24 throw DatabaseException("${see(fileName)} not found")
0
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
25 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
26 }
21
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 19
diff changeset
27 val masterPassword = try {
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 19
diff changeset
28 getPassword(passwordPrompt, !exists)
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 19
diff changeset
29 } catch (e: ConsoleException) {
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 19
diff changeset
30 throw DatabaseException(e.message, cause = e)
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 19
diff changeset
31 }
0
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
32 val conn = DriverManager.getConnection("jdbc:sqlite:$fileName")
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
33 val enc = if (exists) { reuse(conn, masterPassword) } else { init(conn, masterPassword) }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
34 val ret = Database(conn, enc)
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
35 verifyPassword(ret)
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
36 return ret
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
37 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
38
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
39 private fun reuse(connection: Connection, masterPassword: CharArray): Encryption {
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
40 try {
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
41 connection.prepareStatement("select value from blobs where name = ?").use {
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
42 it.setString(1, "salt")
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
43 val result = it.executeQuery()
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
44 if (!result.next()) {
21
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 19
diff changeset
45 throw DatabaseException("corrupt database, missing salt parameter")
0
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
46 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
47 val salt = result.getBytes(1)
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
48 return Encryption(masterPassword, salt)
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
49 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
50 } catch (e: SQLException) {
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
51 e.printStackTrace()
21
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 19
diff changeset
52 throw DatabaseException("unable to reopen database", e)
0
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
53 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
54 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
55
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
56 private fun init(connection: Connection, masterPassword: CharArray): Encryption {
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
57 try {
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
58 connection.createStatement().use { stmt ->
19
7d80cbcb67bb add shlex-style splitter and tests
David Barts <n5jrn@me.com>
parents: 16
diff changeset
59 stmt.executeUpdate("create table integers ( name text not null, value integer )")
7d80cbcb67bb add shlex-style splitter and tests
David Barts <n5jrn@me.com>
parents: 16
diff changeset
60 stmt.executeUpdate("create table reals ( name text not null, value real )")
7d80cbcb67bb add shlex-style splitter and tests
David Barts <n5jrn@me.com>
parents: 16
diff changeset
61 stmt.executeUpdate("create table strings ( name text not null, value text )")
7d80cbcb67bb add shlex-style splitter and tests
David Barts <n5jrn@me.com>
parents: 16
diff changeset
62 stmt.executeUpdate("create table blobs ( name text not null, value blob )")
0
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
63 stmt.executeUpdate(
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
64 "create table passwords (" +
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
65 "id integer not null primary key, " +
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
66 "name blob not null, " +
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
67 "username blob not null, " +
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
68 "password blob not null, " +
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
69 "notes blob, " +
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
70 "created integer, " +
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
71 "modified integer, " +
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
72 "accessed integer )"
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
73 )
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
74 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
75 val salt = ByteArray(SALT_LENGTH).also { SecureRandom().nextBytes(it) }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
76 val encryption = Encryption(masterPassword, salt)
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
77 connection.prepareStatement("insert into blobs (name, value) values (?, ?)").use {
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
78 it.setString(1, "salt")
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
79 it.setBytes(2, salt)
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
80 it.execute()
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
81 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
82 connection.prepareStatement("insert into blobs (name, value) values (?, ?)").use { stmt ->
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
83 stmt.setString(1, "test")
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
84 stmt.setEncryptedString(2, PLAINTEXT, encryption)
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
85 stmt.execute()
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
86 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
87 return encryption
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
88 } catch (e: SQLException) {
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
89 e.printStackTrace()
21
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 19
diff changeset
90 throw DatabaseException("unable to initialize database", e)
0
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
91 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
92 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
93
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
94 private fun verifyPassword(database: Database) {
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
95 try {
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
96 database.connection.prepareStatement("select value from blobs where name = ?").use { stmt ->
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
97 stmt.setString(1, "test")
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
98 val result = stmt.executeQuery()
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
99 if (!result.next()) {
21
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 19
diff changeset
100 throw DatabaseException("corrupt database, missing test parameter")
0
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
101 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
102 val readFromDb = result.getDecryptedString(1, database.encryption)
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
103 if (readFromDb != PLAINTEXT) {
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
104 /* might also get thrown by getDecryptedString if bad */
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
105 throw GeneralSecurityException("bad key!")
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
106 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
107 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
108 } catch (e: SQLException) {
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
109 e.printStackTrace()
21
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 19
diff changeset
110 throw DatabaseException("unable to verify decryption key", e)
0
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
111 } catch (e: GeneralSecurityException) {
21
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 19
diff changeset
112 throw DatabaseException("invalid decryption key", e)
0
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
113 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
114 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
115 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
116
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
117 fun makeKey(name: String): Long = Hashing.hash(encryption.encryptFromString0(name.lowercase()))
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
118 }
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
119
21
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 19
diff changeset
120 class DatabaseException(message: String, cause: Throwable? = null) : MessagedException(message, cause)
ea65ab890f66 More work to support interactive feature.
David Barts <n5jrn@me.com>
parents: 19
diff changeset
121
11
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
122 fun ResultSet.getDecryptedString(columnIndex: Int, encryption: Encryption): String? {
8
698c4a3d758d Some code clean-up.
David Barts <n5jrn@me.com>
parents: 7
diff changeset
123 return encryption.decryptToString(getBytes(columnIndex) ?: return null)
698c4a3d758d Some code clean-up.
David Barts <n5jrn@me.com>
parents: 7
diff changeset
124 }
0
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
125
11
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
126 fun ResultSet.getDecrypted(columnIndex: Int, encryption: Encryption): CharArray? {
8
698c4a3d758d Some code clean-up.
David Barts <n5jrn@me.com>
parents: 7
diff changeset
127 return encryption.decrypt(getBytes(columnIndex) ?: return null)
698c4a3d758d Some code clean-up.
David Barts <n5jrn@me.com>
parents: 7
diff changeset
128 }
0
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
129
11
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
130 fun PreparedStatement.setEncryptedString(columnIndex: Int, value: String?, encryption: Encryption) =
8
698c4a3d758d Some code clean-up.
David Barts <n5jrn@me.com>
parents: 7
diff changeset
131 if (value == null) {
698c4a3d758d Some code clean-up.
David Barts <n5jrn@me.com>
parents: 7
diff changeset
132 setNull(columnIndex, Types.BLOB)
698c4a3d758d Some code clean-up.
David Barts <n5jrn@me.com>
parents: 7
diff changeset
133 } else {
698c4a3d758d Some code clean-up.
David Barts <n5jrn@me.com>
parents: 7
diff changeset
134 setBytes(columnIndex, encryption.encryptFromString(value))
698c4a3d758d Some code clean-up.
David Barts <n5jrn@me.com>
parents: 7
diff changeset
135 }
0
a6cfdffcaa94 Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff changeset
136
11
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
137 fun PreparedStatement.setEncrypted(columnIndex: Int, value: CharArray?, encryption: Encryption) =
8
698c4a3d758d Some code clean-up.
David Barts <n5jrn@me.com>
parents: 7
diff changeset
138 if (value == null) {
698c4a3d758d Some code clean-up.
David Barts <n5jrn@me.com>
parents: 7
diff changeset
139 setNull(columnIndex, Types.BLOB)
698c4a3d758d Some code clean-up.
David Barts <n5jrn@me.com>
parents: 7
diff changeset
140 } else {
698c4a3d758d Some code clean-up.
David Barts <n5jrn@me.com>
parents: 7
diff changeset
141 setBytes(columnIndex, encryption.encrypt(value))
698c4a3d758d Some code clean-up.
David Barts <n5jrn@me.com>
parents: 7
diff changeset
142 }
11
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
143
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
144 fun PreparedStatement.setBytesOrNull(columnIndex: Int, value: ByteArray?) =
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
145 if (value == null) {
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
146 setNull(columnIndex, Types.BLOB)
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
147 } else {
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
148 setBytes(columnIndex, value)
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
149 }
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
150
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
151 fun PreparedStatement.setLongOrNull(columnIndex: Int, value: Long?) =
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
152 if (value == null) {
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
153 setNull(columnIndex, Types.INTEGER)
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
154 } else {
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
155 setLong(columnIndex, value)
c69665ff37d0 Add merge subcommand (untested).
David Barts <n5jrn@me.com>
parents: 8
diff changeset
156 }
15
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
157
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
158 fun PreparedStatement.setDateOrNull(parameterIndex: Int, value: Long?) {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
159 if (value == null || value == 0L) {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
160 setNull(parameterIndex, Types.INTEGER)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
161 } else {
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
162 setLong(parameterIndex, value)
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
163 }
0fc90892a3ae Add password subcommand.
David Barts <n5jrn@me.com>
parents: 11
diff changeset
164 }
16
7a74ae668665 Add export subcommand.
David Barts <n5jrn@me.com>
parents: 15
diff changeset
165