• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

future-architect / uroborosql / #764

13 Aug 2024 03:26PM UTC coverage: 91.218% (+0.02%) from 91.197%
#764

Pull #331

HidekiSugimoto189
add oracle v12-23 and Mariadb 5,10 dialect
Pull Request #331: add oracle v12-23 and Mariadb 5,10 dialect

43 of 46 new or added lines in 8 files covered. (93.48%)

288 existing lines in 22 files now uncovered.

8787 of 9633 relevant lines covered (91.22%)

0.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.5
/src/main/java/jp/co/future/uroborosql/event/subscriber/DumpResultEventSubscriber.java
1
/**
2
 * Copyright (c) 2017-present, Future Corporation
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
package jp.co.future.uroborosql.event.subscriber;
8

9
import java.io.UnsupportedEncodingException;
10
import java.nio.ByteBuffer;
11
import java.nio.CharBuffer;
12
import java.nio.charset.CharacterCodingException;
13
import java.nio.charset.Charset;
14
import java.nio.charset.CoderResult;
15
import java.nio.charset.CodingErrorAction;
16
import java.sql.ResultSet;
17
import java.sql.SQLException;
18
import java.util.ArrayList;
19
import java.util.HashMap;
20
import java.util.Map;
21

22
import org.slf4j.Logger;
23
import org.slf4j.LoggerFactory;
24

25
import jp.co.future.uroborosql.event.AfterSqlQueryEvent;
26
import jp.co.future.uroborosql.utils.ObjectUtils;
27

28
/**
29
 * 実行結果をダンプ出力するイベントサブスクライバ.<br>
30
 *
31
 * このイベントサブスクライバを使用する際は、PreparedStatementを生成する際、ResultSetTypeに
32
 * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code> または<code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
33
 * を指定してください。
34
 *
35
 * @author H.Sugimoto
36
 * @since v1.0.0
37
 *
38
 */
39
public class DumpResultEventSubscriber extends EventSubscriber {
1✔
40
        /** ロガー */
41
        private static final Logger EVENT_LOG = LoggerFactory.getLogger("jp.co.future.uroborosql.event.dumpresult");
1✔
42

43
        /** 文字数計算用のエンコーディング */
44
        private static final String ENCODING_SHIFT_JIS = "Shift-JIS";
45

46
        /**
47
         *
48
         * {@inheritDoc}
49
         *
50
         * @see jp.co.future.uroborosql.event.subscriber.EventSubscriber#initialize()
51
         */
52
        @Override
53
        public void initialize() {
54
                afterSqlQueryListener(this::afterSqlQuery);
1✔
55
        }
1✔
56

57
        void afterSqlQuery(final AfterSqlQueryEvent evt) {
58
                try {
59
                        if (evt.getResultSet().getType() == ResultSet.TYPE_FORWARD_ONLY) {
1✔
UNCOV
60
                                if (EVENT_LOG.isWarnEnabled()) {
×
UNCOV
61
                                        EVENT_LOG.warn(
×
62
                                                        "ResultSet type is TYPE_FORWARD_ONLY. DumpResultEventSubscriber use ResultSet#beforeFirst(). Please Set TYPE_SCROLL_INSENSITIVE or TYPE_SCROLL_SENSITIVE.");
63
                                }
64
                        }
65
                        if (EVENT_LOG.isDebugEnabled()) {
1✔
66
                                EVENT_LOG.debug("{}", displayResult(evt.getResultSet()));
1✔
67
                        }
68
                } catch (SQLException ex) {
×
69
                        EVENT_LOG.warn(ex.getMessage(), ex);
×
70
                }
1✔
71
        }
1✔
72

73
        /**
74
         * 検索結果を表示
75
         *
76
         * @param rs 検索結果のResultSet
77
         * @return 表示文字列
78
         */
79
        private StringBuilder displayResult(final ResultSet rs) {
80
                try {
81
                        var keys = new ArrayList<String>();
1✔
82
                        var maxLengthList = new HashMap<String, Integer>();
1✔
83
                        var rsmd = rs.getMetaData();
1✔
84
                        var columnCount = rsmd.getColumnCount();
1✔
85
                        for (var i = 1; i <= columnCount; i++) {
1✔
86
                                var columnLabel = rsmd.getColumnLabel(i);
1✔
87
                                keys.add(columnLabel);
1✔
88
                                maxLengthList.put(columnLabel, getByteLength(columnLabel));
1✔
89
                        }
90

91
                        var rows = new ArrayList<Map<String, Object>>();
1✔
92

93
                        while (rs.next()) {
1✔
94
                                var data = new HashMap<String, Object>();
1✔
95

96
                                for (var key : keys) {
1✔
97
                                        var val = rs.getObject(key);
1✔
98
                                        data.put(key, val);
1✔
99

100
                                        var currentLength = getByteLength(val);
1✔
101
                                        maxLengthList.compute(key, (k, v) -> v < currentLength ? currentLength : v);
1✔
102
                                }
1✔
103
                                rows.add(data);
1✔
104
                        }
1✔
105

106
                        var builder = new StringBuilder(System.lineSeparator());
1✔
107
                        // ヘッダ部出力
108
                        builder.append("+");
1✔
109
                        for (var key : keys) {
1✔
110
                                builder.append(ObjectUtils.repeat('-', maxLengthList.get(key))).append("+");
1✔
111
                        }
1✔
112
                        builder.append(System.lineSeparator()).append("|");
1✔
113
                        for (var key : keys) {
1✔
114
                                builder.append(fillHeader(key, maxLengthList.get(key))).append("|");
1✔
115
                        }
1✔
116
                        builder.append(System.lineSeparator()).append("+");
1✔
117
                        for (var key : keys) {
1✔
118
                                builder.append(ObjectUtils.repeat('-', maxLengthList.get(key))).append("+");
1✔
119
                        }
1✔
120

121
                        // データ部出力
122

123
                        if (rows.isEmpty()) {
1✔
124
                                builder.append(System.lineSeparator()).append("|");
1✔
125
                                var len = 1;
1✔
126
                                for (var key : keys) {
1✔
127
                                        len = len + maxLengthList.get(key) + 1;
1✔
128
                                }
1✔
129

130
                                if (len >= 13) {
1✔
131
                                        builder.append("empty data.").append(ObjectUtils.repeat(' ', len - 13)).append("|");
1✔
132
                                } else {
133
                                        builder.append("-").append(ObjectUtils.repeat(' ', len - 3)).append("|");
1✔
134
                                }
135
                        } else {
1✔
136
                                for (var row : rows) {
1✔
137
                                        builder.append(System.lineSeparator()).append("|");
1✔
138
                                        for (var key : keys) {
1✔
139
                                                builder.append(fillData(row.get(key), maxLengthList.get(key))).append("|");
1✔
140
                                        }
1✔
141
                                }
1✔
142

143
                        }
144
                        builder.append(System.lineSeparator()).append("+");
1✔
145
                        for (var key : keys) {
1✔
146
                                builder.append(ObjectUtils.repeat('-', maxLengthList.get(key))).append("+");
1✔
147
                        }
1✔
148

149
                        // カーソルを先頭の前に戻す
150
                        if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
1✔
151
                                rs.beforeFirst();
1✔
152
                        }
153

154
                        return builder;
1✔
UNCOV
155
                } catch (Exception ex) {
×
UNCOV
156
                        EVENT_LOG.error(ex.getMessage(), ex);
×
157
                }
158
                return null;
×
159
        }
160

161
        private String fillHeader(final String str, final int length) {
162
                var strLen = getByteLength(str);
1✔
163
                var spaceSize = (length - strLen) / 2;
1✔
164

165
                var spaceStr = ObjectUtils.repeat(' ', spaceSize);
1✔
166
                var ans = spaceStr + str + spaceStr;
1✔
167
                var fillLen = getByteLength(ans);
1✔
168
                if (length > fillLen) {
1✔
169
                        ans = ans + ObjectUtils.repeat(' ', length - fillLen);
1✔
170
                }
171
                return ans;
1✔
172
        }
173

174
        private String fillData(final Object val, final int length) throws CharacterCodingException,
175
                        UnsupportedEncodingException {
176
                var valLen = getByteLength(val);
1✔
177
                var spaceSize = length - valLen;
1✔
178

179
                if (val instanceof Number) {
1✔
180
                        return ObjectUtils.repeat(' ', spaceSize) + getSubstringByte(val, length);
1✔
181
                } else {
182
                        return getSubstringByte(val, length) + ObjectUtils.repeat(' ', spaceSize);
1✔
183
                }
184

185
        }
186

187
        /**
188
         * オブジェクトの文字列表現のバイト数(Shift-JIS換算)を取得する
189
         *
190
         * @param val 計算対象オブジェクト
191
         * @return バイト数。200バイトを超える場合は200を返す
192
         */
193
        private int getByteLength(final Object val) {
194
                if (val == null) {
1✔
UNCOV
195
                        return 4;
×
196
                }
197
                var str = val.toString();
1✔
198
                try {
199
                        var len = str.getBytes(ENCODING_SHIFT_JIS).length;
1✔
200
                        return len <= 200 ? len : 200;
1✔
201
                } catch (UnsupportedEncodingException ex) {
×
UNCOV
202
                        return 1;
×
203
                }
204
        }
205

206
        /**
207
         * 指定したバイト数で文字列をカットする
208
         *
209
         * @param obj 対象オブジェクト
210
         * @param capacity カットするバイト数
211
         * @return String
212
         * @throws CharacterCodingException
213
         * @throws UnsupportedEncodingException
214
         */
215
        private String getSubstringByte(final Object obj, final int capacity) throws CharacterCodingException,
216
                        UnsupportedEncodingException {
217
                var str = obj == null ? "null" : obj.toString();
1✔
218
                if (capacity < 1) {
1✔
UNCOV
219
                        return str;
×
220
                }
221

222
                var ce = Charset.forName(ENCODING_SHIFT_JIS).newEncoder()
1✔
223
                                .onMalformedInput(CodingErrorAction.REPLACE)
1✔
224
                                .onUnmappableCharacter(CodingErrorAction.REPLACE)
1✔
225
                                .reset();
1✔
226
                if (capacity >= ce.maxBytesPerChar() * str.length()) {
1✔
227
                        return str;
1✔
228
                }
229
                var cb = CharBuffer.wrap(new char[Math.min(str.length(), capacity)]);
1✔
230
                str.getChars(0, Math.min(str.length(), cb.length()), cb.array(), 0);
1✔
231

232
                if (capacity >= ce.maxBytesPerChar() * cb.limit()) {
1✔
UNCOV
233
                        return cb.toString();
×
234
                }
235
                var out = ByteBuffer.allocate(capacity);
1✔
236
                ce.reset();
1✔
237
                CoderResult cr = null;
1✔
238
                if (cb.hasRemaining()) {
1✔
239
                        cr = ce.encode(cb, out, true);
1✔
240
                } else {
UNCOV
241
                        cr = CoderResult.UNDERFLOW;
×
242
                }
243
                if (cr.isUnderflow()) {
1✔
244
                        cr = ce.flush(out);
1✔
245
                }
246
                return cb.flip().toString();
1✔
247
        }
248
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc