qortal/src/repository/hsqldb/HSQLDBVotingRepository.java
catbref 5526f9a7f0 More work on integrating CIYAM AT v2
Now using ATv2 dated 20181101172102

ATData now uses byte[] creatorPublicKey instead of String creator.

TransactionData now has hashCode() and equals() methods,
which is needed for new Transaction Comparator,
used to sort transactions within a block,
AT-first, then timestamp, then signature.

AT-Transactions generate their own signatures using SHA2-256 of serialized data.

Arbitrary Transactions try to clean up their files when orphaned.

Deploy AT Transactions now check creation bytes (even for old v1 ATs).

Deprecated Transaction.getBlock() as it doesn't seem used
and would be better to simply have getHeight() rather than
a method that 'knows too much' about Blocks/BlockData.
Corresponding TransactionRepository.getBlockDataFromSignature()
also deprecated.

Loads more comments.

Tidied up some SQL: mainly correcting case,
moving PRIMARY KEY clauses to end of CREATE TABLE,
removing unnecessary columns from indexes.

Added "type" column to TransactionCreatorIndex so users can find
their transactions and optionally filter by type.

In BlockTransactions table, transaction_signature is now UNIQUE
as a transaction cannot be included in more than one block.

Various AT-related HSQLDB table and index changes.

ArbitraryTransactions transformer fixed to always return a list of payments,
even if empty. (Previously could return null which broke things).

Added simplistic block generator.

NOTE: unit tests broken due to pending upgrade to JUnit 5
2018-11-02 10:30:51 +00:00

171 lines
5.7 KiB
Java

package repository.hsqldb;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import data.voting.PollData;
import data.voting.PollOptionData;
import data.voting.VoteOnPollData;
import repository.VotingRepository;
import repository.DataException;
public class HSQLDBVotingRepository implements VotingRepository {
protected HSQLDBRepository repository;
public HSQLDBVotingRepository(HSQLDBRepository repository) {
this.repository = repository;
}
// Polls
@Override
public PollData fromPollName(String pollName) throws DataException {
try (ResultSet resultSet = this.repository.checkedExecute("SELECT description, creator, owner, published FROM Polls WHERE poll_name = ?", pollName)) {
if (resultSet == null)
return null;
String description = resultSet.getString(1);
byte[] creatorPublicKey = resultSet.getBytes(2);
String owner = resultSet.getString(3);
long published = resultSet.getTimestamp(4, Calendar.getInstance(HSQLDBRepository.UTC)).getTime();
try (ResultSet optionsResultSet = this.repository
.checkedExecute("SELECT option_name FROM PollOptions WHERE poll_name = ? ORDER BY option_index ASC", pollName)) {
if (optionsResultSet == null)
return null;
List<PollOptionData> pollOptions = new ArrayList<PollOptionData>();
// NOTE: do-while because checkedExecute() above has already called rs.next() for us
do {
String optionName = optionsResultSet.getString(1);
pollOptions.add(new PollOptionData(optionName));
} while (optionsResultSet.next());
return new PollData(creatorPublicKey, owner, pollName, description, pollOptions, published);
}
} catch (SQLException e) {
throw new DataException("Unable to fetch poll from repository", e);
}
}
@Override
public boolean pollExists(String pollName) throws DataException {
try {
return this.repository.exists("Polls", "poll_name = ?", pollName);
} catch (SQLException e) {
throw new DataException("Unable to check for poll in repository", e);
}
}
@Override
public void save(PollData pollData) throws DataException {
HSQLDBSaver saveHelper = new HSQLDBSaver("Polls");
saveHelper.bind("poll_name", pollData.getPollName()).bind("description", pollData.getDescription()).bind("creator", pollData.getCreatorPublicKey())
.bind("owner", pollData.getOwner()).bind("published", new Timestamp(pollData.getPublished()));
try {
saveHelper.execute(this.repository);
} catch (SQLException e) {
throw new DataException("Unable to save poll into repository", e);
}
// Now attempt to save poll options
List<PollOptionData> pollOptions = pollData.getPollOptions();
for (int optionIndex = 0; optionIndex < pollOptions.size(); ++optionIndex) {
PollOptionData pollOptionData = pollOptions.get(optionIndex);
HSQLDBSaver optionSaveHelper = new HSQLDBSaver("PollOptions");
optionSaveHelper.bind("poll_name", pollData.getPollName()).bind("option_index", optionIndex).bind("option_name", pollOptionData.getOptionName());
try {
optionSaveHelper.execute(this.repository);
} catch (SQLException e) {
throw new DataException("Unable to save poll option into repository", e);
}
}
}
@Override
public void delete(String pollName) throws DataException {
// NOTE: The corresponding rows in PollOptions are deleted automatically by the database thanks to "ON DELETE CASCADE" in the PollOptions' FOREIGN KEY
// definition.
try {
this.repository.delete("Polls", "poll_name = ?", pollName);
} catch (SQLException e) {
throw new DataException("Unable to delete poll from repository", e);
}
}
// Votes
@Override
public List<VoteOnPollData> getVotes(String pollName) throws DataException {
List<VoteOnPollData> votes = new ArrayList<VoteOnPollData>();
try (ResultSet resultSet = this.repository.checkedExecute("SELECT voter, option_index FROM PollVotes WHERE poll_name = ?", pollName)) {
if (resultSet == null)
return votes;
// NOTE: do-while because checkedExecute() above has already called rs.next() for us
do {
byte[] voterPublicKey = resultSet.getBytes(1);
int optionIndex = resultSet.getInt(2);
votes.add(new VoteOnPollData(pollName, voterPublicKey, optionIndex));
} while (resultSet.next());
return votes;
} catch (SQLException e) {
throw new DataException("Unable to fetch poll votes from repository", e);
}
}
@Override
public VoteOnPollData getVote(String pollName, byte[] voterPublicKey) throws DataException {
try (ResultSet resultSet = this.repository.checkedExecute("SELECT option_index FROM PollVotes WHERE poll_name = ? AND voter = ?", pollName,
voterPublicKey)) {
if (resultSet == null)
return null;
int optionIndex = resultSet.getInt(1);
return new VoteOnPollData(pollName, voterPublicKey, optionIndex);
} catch (SQLException e) {
throw new DataException("Unable to fetch poll vote from repository", e);
}
}
@Override
public void save(VoteOnPollData voteOnPollData) throws DataException {
HSQLDBSaver saveHelper = new HSQLDBSaver("PollVotes");
saveHelper.bind("poll_name", voteOnPollData.getPollName()).bind("voter", voteOnPollData.getVoterPublicKey()).bind("option_index",
voteOnPollData.getOptionIndex());
try {
saveHelper.execute(this.repository);
} catch (SQLException e) {
throw new DataException("Unable to save poll vote into repository", e);
}
}
@Override
public void delete(String pollName, byte[] voterPublicKey) throws DataException {
try {
this.repository.delete("PollVotes", "poll_name = ? AND voter = ?", pollName, voterPublicKey);
} catch (SQLException e) {
throw new DataException("Unable to delete poll vote from repository", e);
}
}
}