DataAccess.java

1
/*******************************************************************************
2
 * Copyhacked (H) 2012-2025.
3
 * This program and the accompanying materials
4
 * are made available under no term at all, use it like
5
 * you want, but share and discuss it
6
 * every time possible with every body.
7
 * 
8
 * Contributors:
9
 *      ron190 at ymail dot com - initial implementation
10
 ******************************************************************************/
11
package com.jsql.model.accessible;
12
13
import com.jsql.model.InjectionModel;
14
import com.jsql.model.bean.database.*;
15
import com.jsql.model.bean.util.Interaction;
16
import com.jsql.model.bean.util.Request;
17
import com.jsql.model.exception.AbstractSlidingException;
18
import com.jsql.model.exception.InjectionFailureException;
19
import com.jsql.model.exception.JSqlException;
20
import com.jsql.model.suspendable.SuspendableGetRows;
21
import com.jsql.util.I18nUtil;
22
import com.jsql.util.LogLevelUtil;
23
import org.apache.commons.lang3.StringUtils;
24
import org.apache.logging.log4j.LogManager;
25
import org.apache.logging.log4j.Logger;
26
27
import java.util.ArrayList;
28
import java.util.List;
29
import java.util.regex.Pattern;
30
31
/**
32
 * Database resource object to read name of databases, tables, columns and values
33
 * using most suited injection strategy.
34
 */
35
public class DataAccess {
36
    
37
    private static final Logger LOGGER = LogManager.getRootLogger();
38
    
39
    /**
40
     * Regex characters marking the end of the result of an injection.
41
     * Process stops when this schema is encountered:
42
     * <pre>SQLix01x03x03x07
43
     */
44
    public static final String TRAIL_RGX = "\\x01\\x03\\x03\\x07";
45
    
46
    /**
47
     * Regex character used between each table cells.
48
     * Expected schema of multiple table cells :
49
     * <pre>
50
     * x04[table cell]x05[number of occurrences]x04x06x04[table cell]x05[number of occurrences]x04
51
     */
52
    public static final String SEPARATOR_CELL_RGX = "\\x06";
53
    
54
    /**
55
     * Regex character used between the table cell and the number of occurrence of the cell text.
56
     * Expected schema of a table cell data is
57
     * <pre>x04[table cell]x05[number of occurrences]x04
58
     */
59
    public static final String SEPARATOR_QTE_RGX = "\\x05";
60
61
    /**
62
     * Regex character enclosing a table cell returned by injection.
63
     * It allows to detect the correct end of a table cell data during parsing.
64
     * Expected schema of a table cell data is
65
     * <pre>x04[table cell]x05[number of occurrences]x04
66
     */
67
    public static final String ENCLOSE_VALUE_RGX = "\\x04";
68
    
69
    public static final String LEAD = "SqLi";
70
    public static final String SHELL_LEAD = "${shell.lead}";
71
    public static final String TRAIL = "iLQS";
72
    public static final String SHELL_TRAIL = "${shell.trail}";
73
    
74
    /**
75
     * Regex keywords corresponding to multiline and case-insensitive match.
76
     */
77
    public static final String MODE = "(?si)";
78
    
79
    /**
80
     * Regex schema describing a table cell with firstly the cell content and secondly the number of occurrences
81
     * of the cell text, separated by the reserved character x05 in hexadecimal.
82
     * The range of characters from x01 to x1F are not printable ASCII characters used to parse the data and exclude
83
     * printable characters during parsing.
84
     * Expected schema of a table cell data is
85
     * <pre>x04[table cell]x05[number of occurrences]x04
86
     */
87
    public static final String CELL_TABLE = "([^\\x01-\\x09\\x0B-\\x0C\\x0E-\\x1F]*)"+ DataAccess.SEPARATOR_QTE_RGX +"([^\\x01-\\x09\\x0B-\\x0C\\x0E-\\x1F]*)(\\x08)?";
88
89
    private final InjectionModel injectionModel;
90
    
91
    public DataAccess(InjectionModel injectionModel) {
92
        this.injectionModel = injectionModel;
93
    }
94
    
95
    /**
96
     * Get general database information.<br>
97
     * => version{%}database{%}user{%}CURRENT_USER
98
     */
99
    public void getDatabaseInfos() {
100
        LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, () -> I18nUtil.valueByKey("LOG_FETCHING_INFORMATIONS"));
101
        
102
        var sourcePage = new String[]{ StringUtils.EMPTY };
103
104
        var resultToParse = StringUtils.EMPTY;
105
        try {
106
            resultToParse = new SuspendableGetRows(this.injectionModel).run(
107
                this.injectionModel.getMediatorVendor().getVendor().instance().sqlInfos(),
108
                sourcePage,
109
                false,
110
                0,
111
                MockElement.MOCK,
112
                "metadata"
113
            );
114
        } catch (AbstractSlidingException e) {
115
            resultToParse = DataAccess.getPartialResultAndLog(e, resultToParse);
116
        } catch (Exception e) {  // Catch all exceptions but prevent detecting bug
117
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, e.getMessage(), e);
118
        }
119
120 1 1. getDatabaseInfos : negated conditional → NO_COVERAGE
        if (StringUtils.isEmpty(resultToParse)) {
121 1 1. getDatabaseInfos : removed call to com/jsql/model/InjectionModel::sendResponseFromSite → NO_COVERAGE
            this.injectionModel.sendResponseFromSite("Incorrect metadata", sourcePage[0].trim());
122
        }
123
        
124
        try {
125
            String versionDatabase = resultToParse.split(DataAccess.ENCLOSE_VALUE_RGX)[0].replaceAll("\\s+", StringUtils.SPACE);
126
            String nameDatabase = resultToParse.split(DataAccess.ENCLOSE_VALUE_RGX)[1];
127
            String username = resultToParse.split(DataAccess.ENCLOSE_VALUE_RGX)[2];
128
129
            var infos = String.format(
130
                "Database [%s] on %s [%s] for user [%s]",
131
                nameDatabase,
132
                this.injectionModel.getMediatorVendor().getVendor(),
133
                versionDatabase,
134
                username
135
            );
136
            LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, infos);
137
        } catch (ArrayIndexOutOfBoundsException e) {
138
            LOGGER.log(
139
                LogLevelUtil.CONSOLE_ERROR,
140
                String.format("%s: %s", I18nUtil.valueByKey("LOG_DB_METADATA_INCORRECT"), resultToParse)
141
            );
142
            LOGGER.log(LogLevelUtil.CONSOLE_INFORM, I18nUtil.valueByKey("LOG_DB_METADATA_WARN"));
143
        }
144
    }
145
146
    /**
147
     * Get database names and table counts and send them to the view.<br>
148
     * Use readable text (not hexa) and parse this pattern:<br>
149
     * => hh[database name 1]jj[table count]hhgghh[database name 2]jj[table count]hhggh...hi<br>
150
     * Data window can be cut before the end of the request but the process helps to obtain
151
     * the rest of the unreachable data. The process can be interrupted by the user (stop/pause).
152
     * @return list of databases found
153
     * @throws JSqlException when injection failure or stopped by user
154
     */
155
    public List<Database> listDatabases() throws JSqlException {
156
        LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, () -> I18nUtil.valueByKey("LOG_FETCHING_DATABASES"));
157
        List<Database> databases = new ArrayList<>();
158
        String resultToParse = StringUtils.EMPTY;
159
        
160
        try {
161
            var sourcePage = new String[]{ StringUtils.EMPTY };
162
            resultToParse = new SuspendableGetRows(this.injectionModel).run(
163
                this.injectionModel.getMediatorVendor().getVendor().instance().sqlDatabases(),
164
                sourcePage,
165
                true,
166
                0,
167
                MockElement.MOCK,
168
                "databases"
169
            );
170
        } catch (AbstractSlidingException e) {
171
            resultToParse = DataAccess.getPartialResultAndLog(e, resultToParse);
172
        } catch (Exception e) {  // Catch all exceptions but prevent detecting bug
173
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, e.getMessage(), e);
174
        }
175
176
        // Parse all data we have retrieved
177
        var regexSearch = Pattern.compile(
178
                DataAccess.MODE
179
                + DataAccess.ENCLOSE_VALUE_RGX
180
                + DataAccess.CELL_TABLE
181
                + DataAccess.ENCLOSE_VALUE_RGX
182
            )
183
            .matcher(resultToParse);
184 1 1. listDatabases : negated conditional → NO_COVERAGE
        if (!regexSearch.find()) {
185
            throw new InjectionFailureException("No match while injecting databases");
186
        }
187
        
188
        regexSearch.reset();
189
        // Build an array of Database objects from the data we have parsed
190 1 1. listDatabases : negated conditional → NO_COVERAGE
        while (regexSearch.find()) {
191
            String databaseName = regexSearch.group(1);
192
            String tableCount = regexSearch.group(2);
193
194
            var newDatabase = new Database(databaseName, tableCount);
195
            databases.add(newDatabase);
196
        }
197
198
        var request = new Request();
199 1 1. listDatabases : removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE
        request.setMessage(Interaction.ADD_DATABASES);
200 1 1. listDatabases : removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE
        request.setParameters(databases);
201 1 1. listDatabases : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(request);
202 1 1. listDatabases : replaced return value with Collections.emptyList for com/jsql/model/accessible/DataAccess::listDatabases → NO_COVERAGE
        return databases;
203
    }
204
205
    /**
206
     * Get tables name and row count and send them to the view.<br>
207
     * Use readable text (not hexa) and parse this pattern:<br>
208
     * => hh[table name 1]jj[rows count]hhgghh[table name 2]jj[rows count]hhggh...hi<br>
209
     * Data window can be cut before the end of the request but the process helps to obtain
210
     * the rest of the unreachable data. The process can be interrupted by the user (stop/pause).
211
     * @param database which contains tables to find
212
     * @return list of tables found
213
     * @throws JSqlException when injection failure or stopped by user
214
     */
215
    public List<Table> listTables(Database database) throws JSqlException {
216
        // Reset stoppedByUser if list of Databases is partial
217
        // and some Tables are still reachable
218 1 1. listTables : removed call to com/jsql/model/InjectionModel::setIsStoppedByUser → NO_COVERAGE
        this.injectionModel.setIsStoppedByUser(false);
219
        
220
        // Inform the view that database has just been used
221
        var requestStartProgress = new Request();
222 1 1. listTables : removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE
        requestStartProgress.setMessage(Interaction.START_PROGRESS);
223 1 1. listTables : removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE
        requestStartProgress.setParameters(database);
224 1 1. listTables : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(requestStartProgress);
225
226
        var tableCount = Integer.toString(database.getChildCount());
227
        
228
        String resultToParse = StringUtils.EMPTY;
229
        try {
230
            var pageSource = new String[]{ StringUtils.EMPTY };
231
            resultToParse = new SuspendableGetRows(this.injectionModel).run(
232
                this.injectionModel.getMediatorVendor().getVendor().instance().sqlTables(database),
233
                pageSource,
234
                true,
235
                Integer.parseInt(tableCount),
236
                database,
237
                "tables"
238
            );
239
        } catch (AbstractSlidingException e) {
240
            resultToParse = DataAccess.getPartialResultAndLog(e, resultToParse);
241
        } catch (Exception e) {  // Catch all exceptions but prevent detecting bug
242
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, e.getMessage(), e);
243
        }
244
245
        // Parse all the data we have retrieved
246
        var regexSearch = Pattern.compile(
247
                DataAccess.MODE
248
                + DataAccess.ENCLOSE_VALUE_RGX
249
                + DataAccess.CELL_TABLE
250
                + DataAccess.ENCLOSE_VALUE_RGX
251
            )
252
            .matcher(resultToParse);
253
        
254
        var requestEndProgress = new Request();
255 1 1. listTables : removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE
        requestEndProgress.setMessage(Interaction.END_PROGRESS);
256 1 1. listTables : removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE
        requestEndProgress.setParameters(database);
257 1 1. listTables : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(requestEndProgress);
258
        
259 1 1. listTables : negated conditional → NO_COVERAGE
        if (!regexSearch.find()) {
260
            throw new InjectionFailureException("No match while injecting tables");
261
        }
262
        regexSearch.reset();
263
        
264
        List<Table> tables = new ArrayList<>();
265
        
266
        // Build an array of Table objects from the data we have parsed
267 1 1. listTables : negated conditional → NO_COVERAGE
        while (regexSearch.find()) {
268
            String tableName = regexSearch.group(1);
269
            String rowCount = regexSearch.group(2);
270
            
271
            var newTable = new Table(tableName, rowCount, database);
272
            tables.add(newTable);
273
        }
274
        
275
        var requestAddTables = new Request();
276 1 1. listTables : removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE
        requestAddTables.setMessage(Interaction.ADD_TABLES);
277 1 1. listTables : removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE
        requestAddTables.setParameters(tables);
278 1 1. listTables : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(requestAddTables);
279 1 1. listTables : replaced return value with Collections.emptyList for com/jsql/model/accessible/DataAccess::listTables → NO_COVERAGE
        return tables;
280
    }
281
282
    /**
283
     * Get column names and send them to the view.<br>
284
     * Use readable text (not hexa) and parse this pattern with 2nd member forced to 31 (1 in ascii):<br>
285
     * => hh[column name 1]jj[31]hhgghh[column name 2]jj[31]hhggh...hi<br>
286
     * Data window can be cut before the end of the request but the process helps to obtain
287
     * the rest of the unreachable data. The process can be interrupted by the user (stop/pause).
288
     * @param table which contains columns to find
289
     * @return list of columns found
290
     * @throws JSqlException when injection failure or stopped by user
291
     */
292
    public List<Column> listColumns(Table table) throws JSqlException {
293
        List<Column> columns = new ArrayList<>();
294
        
295
        // Inform the view that table has just been used
296
        var requestStartProgress = new Request();
297 1 1. listColumns : removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE
        requestStartProgress.setMessage(Interaction.START_INDETERMINATE_PROGRESS);
298 1 1. listColumns : removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE
        requestStartProgress.setParameters(table);
299 1 1. listColumns : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(requestStartProgress);
300
301
        String resultToParse = StringUtils.EMPTY;
302
        
303
        try {
304
            var pageSource = new String[]{ StringUtils.EMPTY };
305
            resultToParse = new SuspendableGetRows(this.injectionModel).run(
306
                this.injectionModel.getMediatorVendor().getVendor().instance().sqlColumns(table),
307
                pageSource,
308
                true,
309
                0,
310
                table,
311
                "columns"
312
            );
313
        } catch (AbstractSlidingException e) {
314
            resultToParse = DataAccess.getPartialResultAndLog(e, resultToParse);
315
        } catch (Exception e) {  // Catch all exceptions but prevent detecting bug
316
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, e.getMessage(), e);
317
        }
318
319
        // Build SQLite columns
320 1 1. listColumns : negated conditional → NO_COVERAGE
        if (this.injectionModel.getMediatorVendor().isSqlite()) {
321
            resultToParse = this.injectionModel.getMediatorVendor().getSqlite().transformSqlite(resultToParse);
322
        }
323
        
324
        // Parse all the data we have retrieved
325
        var regexSearch = Pattern.compile(
326
                DataAccess.MODE
327
                + DataAccess.ENCLOSE_VALUE_RGX
328
                + DataAccess.CELL_TABLE
329
                + DataAccess.ENCLOSE_VALUE_RGX
330
            )
331
            .matcher(resultToParse);
332
333
        var requestEndProgress = new Request();
334 1 1. listColumns : removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE
        requestEndProgress.setMessage(Interaction.END_INDETERMINATE_PROGRESS);
335 1 1. listColumns : removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE
        requestEndProgress.setParameters(table);
336 1 1. listColumns : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(requestEndProgress);
337
338 1 1. listColumns : negated conditional → NO_COVERAGE
        if (!regexSearch.find()) {
339
            throw new InjectionFailureException("No match while injecting columns");
340
        }
341
342
        regexSearch.reset();
343
344
        // Build an array of Column objects from the data we have parsed
345 1 1. listColumns : negated conditional → NO_COVERAGE
        while (regexSearch.find()) {
346
            String nameColumn = regexSearch.group(1);
347
            var column = new Column(nameColumn, table);
348
            columns.add(column);
349
        }
350
351
        var requestAddColumns = new Request();
352 1 1. listColumns : removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE
        requestAddColumns.setMessage(Interaction.ADD_COLUMNS);
353 1 1. listColumns : removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE
        requestAddColumns.setParameters(columns);
354 1 1. listColumns : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(requestAddColumns);
355 1 1. listColumns : replaced return value with Collections.emptyList for com/jsql/model/accessible/DataAccess::listColumns → NO_COVERAGE
        return columns;
356
    }
357
358
    /**
359
     * Get table values and count each occurrence and send it to the view.<br>
360
     * Values are on clear text (not hexa) and follows this window pattern<br>
361
     * => hh[value 1]jj[count]hhgghh[value 2]jj[count]hhggh...hi<br>
362
     * Data window can be cut before the end of the request but the process helps to obtain
363
     * the rest of the unreachable data. The process can be interrupted by the user (stop/pause).
364
     * @param columnsBean choice by the user
365
     * @return a 2x2 table containing values by columns
366
     * @throws JSqlException when injection failure or stopped by user
367
     */
368
    public String[][] listValues(List<Column> columnsBean) throws JSqlException {
369
        var databaseBean = (Database) columnsBean.get(0).getParent().getParent();
370
        var tableBean = (Table) columnsBean.get(0).getParent();
371
        int rowCount = columnsBean.get(0).getParent().getChildCount();
372
373
        // Inform the view that table has just been used
374
        var request = new Request();
375 1 1. listValues : removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE
        request.setMessage(Interaction.START_PROGRESS);
376 1 1. listValues : removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE
        request.setParameters(tableBean);
377 1 1. listValues : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(request);
378
379
        // Build an array of column names
380
        List<String> columnsName = new ArrayList<>();
381
        for (AbstractElementDatabase columnBean: columnsBean) {
382
            columnsName.add(columnBean.toString());
383
        }
384
385
        // From that array, build the SQL fields nicely
386
        // => col1{%}col2...
387
        // ==> trim(ifnull(`col1`,0x00)),0x7f,trim(ifnull(`Col2`,0x00))...
388
        String[] columns = columnsName.toArray(new String[0]);
389
390
        List<List<String>> listValues = this.getRows(databaseBean, tableBean, rowCount, columns);
391
392
        // Add the default title to the columns: row number, occurrence
393 1 1. listValues : removed call to java/util/List::add → NO_COVERAGE
        columnsName.add(0, StringUtils.EMPTY);
394 1 1. listValues : removed call to java/util/List::add → NO_COVERAGE
        columnsName.add(0, StringUtils.EMPTY);
395
396
        String[][] table = this.getTable(columnsName, listValues);
397
398
        columns = columnsName.toArray(new String[0]);
399
        
400
        // Group the columns names, values and Table object in one array
401
        var objectData = new Object[]{ columns, table, tableBean };
402
403
        var requestCreateValuesTab = new Request();
404 1 1. listValues : removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE
        requestCreateValuesTab.setMessage(Interaction.CREATE_VALUES_TAB);
405 1 1. listValues : removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE
        requestCreateValuesTab.setParameters(objectData);
406 1 1. listValues : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(requestCreateValuesTab);
407
408
        var requestEndProgress = new Request();
409 1 1. listValues : removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE
        requestEndProgress.setMessage(Interaction.END_PROGRESS);
410 1 1. listValues : removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE
        requestEndProgress.setParameters(tableBean);
411 1 1. listValues : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
        this.injectionModel.sendToViews(requestEndProgress);
412 1 1. listValues : replaced return value with null for com/jsql/model/accessible/DataAccess::listValues → NO_COVERAGE
        return table;
413
    }
414
415
    private List<List<String>> getRows(Database database, Table table, int rowCount, String[] columns) throws InjectionFailureException {
416
        String resultToParse = StringUtils.EMPTY;
417
        
418
        try {
419
            var pageSource = new String[]{ StringUtils.EMPTY };
420
            resultToParse = new SuspendableGetRows(this.injectionModel).run(
421
                this.injectionModel.getMediatorVendor().getVendor().instance().sqlRows(columns, database, table),
422
                pageSource,
423
                true,
424
                rowCount,
425
                table,
426
                "rows"
427
            );
428
        } catch (AbstractSlidingException e) {  // Catch all exceptions but prevent detecting bug
429
            resultToParse = DataAccess.getPartialResultAndLog(e, resultToParse);
430
        } catch (Exception e) {
431
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, e.getMessage(), e);
432
        }
433 1 1. getRows : replaced return value with Collections.emptyList for com/jsql/model/accessible/DataAccess::getRows → NO_COVERAGE
        return SuspendableGetRows.parse(resultToParse);
434
    }
435
436
    private static String getPartialResultAndLog(AbstractSlidingException e, String resultToParse) {
437
        LOGGER.log(LogLevelUtil.CONSOLE_ERROR, e.getMessage());
438
439
        // Get pieces of data already retrieved instead of losing them
440 1 1. getPartialResultAndLog : negated conditional → NO_COVERAGE
        if (StringUtils.isNotEmpty(e.getSlidingWindowAllRows())) {
441
            resultToParse = e.getSlidingWindowAllRows();
442 1 1. getPartialResultAndLog : negated conditional → NO_COVERAGE
        } else if (StringUtils.isNotEmpty(e.getSlidingWindowCurrentRows())) {
443
            resultToParse = e.getSlidingWindowCurrentRows();
444
        }
445 1 1. getPartialResultAndLog : replaced return value with "" for com/jsql/model/accessible/DataAccess::getPartialResultAndLog → NO_COVERAGE
        return resultToParse;
446
    }
447
448
    private String[][] getTable(List<String> columnsName, List<List<String>> values) {
449
        // Build a proper 2D array from the data
450
        var table = new String[values.size()][columnsName.size()];
451
        
452 2 1. getTable : changed conditional boundary → NO_COVERAGE
2. getTable : negated conditional → NO_COVERAGE
        for (var indexRow = 0 ; indexRow < values.size() ; indexRow++) {
453
            var isIncomplete = false;
454
            
455 2 1. getTable : negated conditional → NO_COVERAGE
2. getTable : changed conditional boundary → NO_COVERAGE
            for (var indexColumn = 0 ; indexColumn < columnsName.size() ; indexColumn++) {
456
                try {
457
                    table[indexRow][indexColumn] = values.get(indexRow).get(indexColumn);
458
                } catch (IndexOutOfBoundsException e) {
459
                    isIncomplete = true;
460
                    LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, I18nUtil.valueByKey("LOG_LIST_VALUES_INCOMPLETE"));
461
                    LOGGER.log(LogLevelUtil.IGNORE, e);
462
                }
463
            }
464
            
465 1 1. getTable : negated conditional → NO_COVERAGE
            if (isIncomplete) {
466
                int logIndexRow = indexRow;
467
                LOGGER.log(
468
                    LogLevelUtil.CONSOLE_ERROR,
469
                    "{}{}: ",
470 1 1. lambda$getTable$2 : replaced return value with null for com/jsql/model/accessible/DataAccess::lambda$getTable$2 → NO_COVERAGE
                    () -> I18nUtil.valueByKey("LOG_LIST_VALUES_TOO_LONG"),
471 2 1. lambda$getTable$3 : replaced return value with null for com/jsql/model/accessible/DataAccess::lambda$getTable$3 → NO_COVERAGE
2. lambda$getTable$3 : Replaced integer addition with subtraction → NO_COVERAGE
                    () -> logIndexRow + 1
472
                );
473
474
                LOGGER.log(
475
                    LogLevelUtil.CONSOLE_ERROR,
476 1 1. lambda$getTable$4 : replaced return value with null for com/jsql/model/accessible/DataAccess::lambda$getTable$4 → NO_COVERAGE
                    () -> String.join(
477
                        ", ",
478
                        values.get(logIndexRow).toArray(new String[0])
479
                    )
480
                );
481
            }
482
        }
483 1 1. getTable : replaced return value with null for com/jsql/model/accessible/DataAccess::getTable → NO_COVERAGE
        return table;
484
    }
485
}

Mutations

120

1.1
Location : getDatabaseInfos
Killed by : none
negated conditional → NO_COVERAGE

121

1.1
Location : getDatabaseInfos
Killed by : none
removed call to com/jsql/model/InjectionModel::sendResponseFromSite → NO_COVERAGE

184

1.1
Location : listDatabases
Killed by : none
negated conditional → NO_COVERAGE

190

1.1
Location : listDatabases
Killed by : none
negated conditional → NO_COVERAGE

199

1.1
Location : listDatabases
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

200

1.1
Location : listDatabases
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

201

1.1
Location : listDatabases
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

202

1.1
Location : listDatabases
Killed by : none
replaced return value with Collections.emptyList for com/jsql/model/accessible/DataAccess::listDatabases → NO_COVERAGE

218

1.1
Location : listTables
Killed by : none
removed call to com/jsql/model/InjectionModel::setIsStoppedByUser → NO_COVERAGE

222

1.1
Location : listTables
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

223

1.1
Location : listTables
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

224

1.1
Location : listTables
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

255

1.1
Location : listTables
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

256

1.1
Location : listTables
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

257

1.1
Location : listTables
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

259

1.1
Location : listTables
Killed by : none
negated conditional → NO_COVERAGE

267

1.1
Location : listTables
Killed by : none
negated conditional → NO_COVERAGE

276

1.1
Location : listTables
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

277

1.1
Location : listTables
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

278

1.1
Location : listTables
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

279

1.1
Location : listTables
Killed by : none
replaced return value with Collections.emptyList for com/jsql/model/accessible/DataAccess::listTables → NO_COVERAGE

297

1.1
Location : listColumns
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

298

1.1
Location : listColumns
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

299

1.1
Location : listColumns
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

320

1.1
Location : listColumns
Killed by : none
negated conditional → NO_COVERAGE

334

1.1
Location : listColumns
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

335

1.1
Location : listColumns
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

336

1.1
Location : listColumns
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

338

1.1
Location : listColumns
Killed by : none
negated conditional → NO_COVERAGE

345

1.1
Location : listColumns
Killed by : none
negated conditional → NO_COVERAGE

352

1.1
Location : listColumns
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

353

1.1
Location : listColumns
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

354

1.1
Location : listColumns
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

355

1.1
Location : listColumns
Killed by : none
replaced return value with Collections.emptyList for com/jsql/model/accessible/DataAccess::listColumns → NO_COVERAGE

375

1.1
Location : listValues
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

376

1.1
Location : listValues
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

377

1.1
Location : listValues
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

393

1.1
Location : listValues
Killed by : none
removed call to java/util/List::add → NO_COVERAGE

394

1.1
Location : listValues
Killed by : none
removed call to java/util/List::add → NO_COVERAGE

404

1.1
Location : listValues
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

405

1.1
Location : listValues
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

406

1.1
Location : listValues
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

409

1.1
Location : listValues
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

410

1.1
Location : listValues
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

411

1.1
Location : listValues
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

412

1.1
Location : listValues
Killed by : none
replaced return value with null for com/jsql/model/accessible/DataAccess::listValues → NO_COVERAGE

433

1.1
Location : getRows
Killed by : none
replaced return value with Collections.emptyList for com/jsql/model/accessible/DataAccess::getRows → NO_COVERAGE

440

1.1
Location : getPartialResultAndLog
Killed by : none
negated conditional → NO_COVERAGE

442

1.1
Location : getPartialResultAndLog
Killed by : none
negated conditional → NO_COVERAGE

445

1.1
Location : getPartialResultAndLog
Killed by : none
replaced return value with "" for com/jsql/model/accessible/DataAccess::getPartialResultAndLog → NO_COVERAGE

452

1.1
Location : getTable
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : getTable
Killed by : none
negated conditional → NO_COVERAGE

455

1.1
Location : getTable
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : getTable
Killed by : none
changed conditional boundary → NO_COVERAGE

465

1.1
Location : getTable
Killed by : none
negated conditional → NO_COVERAGE

470

1.1
Location : lambda$getTable$2
Killed by : none
replaced return value with null for com/jsql/model/accessible/DataAccess::lambda$getTable$2 → NO_COVERAGE

471

1.1
Location : lambda$getTable$3
Killed by : none
replaced return value with null for com/jsql/model/accessible/DataAccess::lambda$getTable$3 → NO_COVERAGE

2.2
Location : lambda$getTable$3
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

476

1.1
Location : lambda$getTable$4
Killed by : none
replaced return value with null for com/jsql/model/accessible/DataAccess::lambda$getTable$4 → NO_COVERAGE

483

1.1
Location : getTable
Killed by : none
replaced return value with null for com/jsql/model/accessible/DataAccess::getTable → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.19.1