Skip to content

Commit 560c7ca

Browse files
committed
BugFix: Avoid constructing overlength sql
Problem: If you happen to have a very big BMS directory, this exception might occur: ``` 严重: スコア取得時の例外:[SQLITE_TOOBIG] String or BLOB exceeds size limit (statement too long) Query: SELECT * FROM score WHERE sha256 IN (...)` ``` And the whole sqlite query statement would be printed in log file. This commit fixed two overlength sql generate code place by forcing them to query data chunk by chunk. And one chunk size is set to be 1000.
1 parent 0d715c7 commit 560c7ca

File tree

2 files changed

+45
-22
lines changed

2 files changed

+45
-22
lines changed

core/src/bms/player/beatoraja/ScoreDatabaseAccessor.java

+21-10
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public class ScoreDatabaseAccessor extends SQLiteDatabaseAccessor {
2626
private final ResultSetHandler<List<PlayerInformation>> infoHandler = new BeanListHandler<PlayerInformation>(PlayerInformation.class);
2727
private final ResultSetHandler<List<ScoreData>> scoreHandler = new BeanListHandler<ScoreData>(ScoreData.class);
2828
private final ResultSetHandler<List<PlayerData>> playerHandler = new BeanListHandler<PlayerData>(PlayerData.class);
29+
private static final int LOAD_CHUNK_SIZE = 1000;
2930

3031
public ScoreDatabaseAccessor(String path) throws ClassNotFoundException {
3132
super(new Table("info",
@@ -157,17 +158,27 @@ public void getScoreDatas(ScoreDataCollector collector, SongData[] songs, int mo
157158

158159
private void getScoreDatas(ScoreDataCollector collector, SongData[] songs, int mode, StringBuilder str, boolean hasln) {
159160
try {
160-
for (SongData song : songs) {
161-
if((hasln && song.hasUndefinedLongNote()) || (!hasln && !song.hasUndefinedLongNote())) {
162-
if (str.length() > 0) {
163-
str.append(',');
161+
int songLength = songs.length;
162+
int chunkLength = (songLength + LOAD_CHUNK_SIZE - 1) / LOAD_CHUNK_SIZE;
163+
List<ScoreData> scores = new ArrayList<>();
164+
for (int i = 0; i < chunkLength;++i) {
165+
// [i * CHUNK_SIZE, min(length, (i + 1) * CHUNK_SIZE)
166+
final int L = i * LOAD_CHUNK_SIZE, R = Math.min(songLength, (i + 1) * LOAD_CHUNK_SIZE);
167+
for (int j = L; j < R;++j) {
168+
SongData song = songs[j];
169+
if((hasln && song.hasUndefinedLongNote()) || (!hasln && !song.hasUndefinedLongNote())) {
170+
if (str.length() > 0) {
171+
str.append(',');
172+
}
173+
str.append('\'').append(song.getSha256()).append('\'');
164174
}
165-
str.append('\'').append(song.getSha256()).append('\'');
166175
}
167-
}
168176

169-
List<ScoreData> scores = Validatable.removeInvalidElements(qr
170-
.query("SELECT * FROM score WHERE sha256 IN (" + str.toString() + ") AND mode = " + mode, scoreHandler));
177+
List<ScoreData> subScores = Validatable.removeInvalidElements(qr
178+
.query("SELECT * FROM score WHERE sha256 IN (" + str.toString() + ") AND mode = " + mode, scoreHandler));
179+
str.setLength(0);
180+
scores.addAll(subScores);
181+
}
171182
for(SongData song : songs) {
172183
if((hasln && song.hasUndefinedLongNote()) || (!hasln && !song.hasUndefinedLongNote())) {
173184
boolean b = true;
@@ -179,8 +190,8 @@ private void getScoreDatas(ScoreDataCollector collector, SongData[] songs, int m
179190
}
180191
}
181192
if(b) {
182-
collector.collect(song, null);
183-
}
193+
collector.collect(song, null);
194+
}
184195
}
185196
}
186197
} catch (Exception e) {

core/src/bms/player/beatoraja/song/SongInformationAccessor.java

+24-12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.sql.Connection;
44
import java.sql.SQLException;
5+
import java.util.ArrayList;
56
import java.util.List;
67
import java.util.logging.Logger;
78

@@ -33,6 +34,7 @@ public class SongInformationAccessor extends SQLiteDatabaseAccessor {
3334
private final QueryRunner qr;
3435

3536
private Connection conn;
37+
private final static int LOAD_CHUNK_SIZE = 1000;
3638

3739
public SongInformationAccessor(String filepath) throws ClassNotFoundException {
3840
super(new Table("information",
@@ -89,21 +91,31 @@ public SongInformation getInformation(String sha256) {
8991

9092
public void getInformation(SongData[] songs) {
9193
try {
92-
StringBuilder str = new StringBuilder(songs.length * 64);
93-
for (SongData song : songs) {
94-
if(song.getSha256() != null) {
95-
if (str.length() > 0) {
96-
str.append(',');
94+
int songLength = songs.length;
95+
int chunkLength = (songLength + LOAD_CHUNK_SIZE - 1) / LOAD_CHUNK_SIZE;
96+
List<SongInformation> infos = new ArrayList<>();
97+
for (int i = 0; i < chunkLength;++i) {
98+
// [i * CHUNK_SIZE, min(length, (i + 1) * CHUNK_SIZE)
99+
final int L = i * LOAD_CHUNK_SIZE, R = Math.min(songLength, (i + 1) * LOAD_CHUNK_SIZE);
100+
for (int j = L; j < R; ++j) {
101+
SongData song = songs[j];
102+
StringBuilder str = new StringBuilder(songs.length * 64);
103+
if (song.getSha256() != null) {
104+
if (str.length() > 0) {
105+
str.append(',');
106+
}
107+
str.append('\'').append(song.getSha256()).append('\'');
97108
}
98-
str.append('\'').append(song.getSha256()).append('\'');
109+
110+
List<SongInformation> subInfos = Validatable.removeInvalidElements(qr
111+
.query("SELECT * FROM information WHERE sha256 IN (" + str + ")", songhandler));
112+
infos.addAll(subInfos);
113+
str.setLength(0);
99114
}
100115
}
101-
102-
List<SongInformation> infos = Validatable.removeInvalidElements(qr
103-
.query("SELECT * FROM information WHERE sha256 IN (" + str.toString() + ")", songhandler));
104-
for(SongData song : songs) {
105-
for(SongInformation info : infos) {
106-
if(info.getSha256().equals(song.getSha256())) {
116+
for (SongData song : songs) {
117+
for (SongInformation info : infos) {
118+
if (info.getSha256().equals(song.getSha256())) {
107119
song.setInformation(info);
108120
break;
109121
}

0 commit comments

Comments
 (0)