|
9 | 9 | */ |
10 | 10 | package net.sf.jsqlparser.statement; |
11 | 11 |
|
12 | | -import net.sf.jsqlparser.JSQLParserException; |
13 | | -import net.sf.jsqlparser.parser.CCJSqlParserUtil; |
14 | | -import net.sf.jsqlparser.statement.select.PlainSelect; |
15 | | -import org.junit.jupiter.api.Assertions; |
16 | | -import org.junit.jupiter.api.Test; |
17 | | - |
18 | 12 | import java.io.ByteArrayInputStream; |
19 | 13 | import java.io.ByteArrayOutputStream; |
20 | 14 | import java.io.IOException; |
21 | 15 | import java.io.ObjectInputStream; |
22 | 16 | import java.io.ObjectOutputStream; |
| 17 | +import java.math.BigDecimal; |
| 18 | +import java.util.stream.Stream; |
| 19 | +import net.sf.jsqlparser.JSQLParserException; |
| 20 | +import net.sf.jsqlparser.expression.SpannerInterleaveIn; |
| 21 | +import net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect; |
| 22 | +import net.sf.jsqlparser.parser.CCJSqlParserUtil; |
| 23 | +import net.sf.jsqlparser.schema.Table; |
| 24 | +import net.sf.jsqlparser.statement.create.table.CreateTable; |
| 25 | +import net.sf.jsqlparser.statement.select.JoinHint; |
| 26 | +import net.sf.jsqlparser.statement.select.PlainSelect; |
| 27 | +import net.sf.jsqlparser.statement.select.SampleClause; |
| 28 | +import net.sf.jsqlparser.test.TestUtils; |
| 29 | +import org.junit.jupiter.api.Assertions; |
| 30 | +import org.junit.jupiter.api.Test; |
| 31 | +import org.junit.jupiter.params.ParameterizedTest; |
| 32 | +import org.junit.jupiter.params.provider.Arguments; |
| 33 | +import org.junit.jupiter.params.provider.MethodSource; |
| 34 | +import org.junit.jupiter.params.provider.ValueSource; |
23 | 35 |
|
24 | 36 | public class SerializationTest { |
25 | 37 | @Test |
@@ -49,4 +61,182 @@ void serializeWithItem() throws JSQLParserException, IOException, ClassNotFoundE |
49 | 61 | "The deserialized object should be equal to the original"); |
50 | 62 | } |
51 | 63 |
|
| 64 | + @ParameterizedTest |
| 65 | + @ValueSource(strings = {"LOOP", "HASH", "MERGE", "REMOTE"}) |
| 66 | + void serializeSqlServerJoinHint(String keyword) throws Exception { |
| 67 | + PlainSelect original = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed( |
| 68 | + "SELECT a.id FROM a INNER " + keyword + " JOIN b ON a.id = b.id"); |
| 69 | + PlainSelect copy = roundTrip(original); |
| 70 | + JoinHint hint = copy.getJoins().get(0).getJoinHint(); |
| 71 | + Assertions.assertEquals(keyword, hint.getKeyword()); |
| 72 | + Assertions.assertEquals(JoinHint.Position.BEFORE_JOIN, hint.getPosition()); |
| 73 | + Assertions.assertEquals("b", ((Table) copy.getJoins().get(0).getFromItem()).getName()); |
| 74 | + Assertions.assertEquals("a.id = b.id", |
| 75 | + copy.getJoins().get(0).getOnExpressions().iterator().next().toString()); |
| 76 | + } |
| 77 | + |
| 78 | + @ParameterizedTest |
| 79 | + @ValueSource(strings = {"shuffle", "BROADCAST"}) |
| 80 | + void serializeDorisJoinHint(String keyword) throws Exception { |
| 81 | + PlainSelect original = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed( |
| 82 | + "SELECT a.id FROM a LEFT JOIN [" + keyword + "] b USING (id)", false, |
| 83 | + parser -> parser.withDialect(Dialect.DORIS)); |
| 84 | + PlainSelect copy = roundTrip(original); |
| 85 | + JoinHint hint = copy.getJoins().get(0).getJoinHint(); |
| 86 | + Assertions.assertEquals(keyword, hint.getKeyword()); |
| 87 | + Assertions.assertEquals(JoinHint.Position.AFTER_JOIN, hint.getPosition()); |
| 88 | + Assertions.assertEquals("id", |
| 89 | + copy.getJoins().get(0).getUsingColumns().get(0).getColumnName()); |
| 90 | + Assertions.assertTrue(copy.getJoins().get(0).isLeft()); |
| 91 | + } |
| 92 | + |
| 93 | + static Stream<Arguments> samplingClauses() { |
| 94 | + return Stream.of( |
| 95 | + Arguments.of("TABLESAMPLE BERNOULLI (10)", |
| 96 | + new SampleClause("TABLESAMPLE", "BERNOULLI", 10L, null, null, null)), |
| 97 | + Arguments.of("TABLESAMPLE SYSTEM (10.5 PERCENT) REPEATABLE (7)", |
| 98 | + new SampleClause("TABLESAMPLE", "SYSTEM", 10.5, "PERCENT", 7L, null)), |
| 99 | + Arguments.of("SAMPLE (99)", |
| 100 | + new SampleClause("SAMPLE", null, 99L, null, null, null)), |
| 101 | + Arguments.of("SAMPLE BLOCK (99.1) SEED (10.1)", |
| 102 | + new SampleClause("SAMPLE", "BLOCK", 99.1, null, null, 10.1)), |
| 103 | + Arguments.of("SAMPLE 0.1 OFFSET 1000", |
| 104 | + new SampleClause("SAMPLE", null, 0.1, null, null, null, false, 1000L)), |
| 105 | + Arguments.of("USING SAMPLE 10%", |
| 106 | + new SampleClause("USING SAMPLE", null, 10L, "%", null, null, false, null)), |
| 107 | + Arguments.of("USING SAMPLE 10 ROWS (system, 377)", |
| 108 | + new SampleClause("USING SAMPLE", "SYSTEM", 10L, "ROWS", null, 377L, |
| 109 | + false, null).setMethodInBrackets(true)), |
| 110 | + Arguments.of("USING SAMPLE RESERVOIR (50 ROWS)", |
| 111 | + new SampleClause("USING SAMPLE", "RESERVOIR", 50L, "ROWS", null, null))); |
| 112 | + } |
| 113 | + |
| 114 | + @ParameterizedTest |
| 115 | + @MethodSource("samplingClauses") |
| 116 | + void serializeTableSampleClause(String clause, SampleClause expected) throws Exception { |
| 117 | + PlainSelect original = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed( |
| 118 | + "SELECT id FROM events " + clause + " WHERE id > 0"); |
| 119 | + assertSampleClause(expected, ((Table) original.getFromItem()).getSampleClause()); |
| 120 | + PlainSelect copy = roundTrip(original); |
| 121 | + assertSampleClause(expected, ((Table) copy.getFromItem()).getSampleClause()); |
| 122 | + Assertions.assertEquals("events", ((Table) copy.getFromItem()).getName()); |
| 123 | + Assertions.assertEquals("id > 0", copy.getWhere().toString()); |
| 124 | + Assertions.assertEquals("id", copy.getSelectItem(0).toString()); |
| 125 | + } |
| 126 | + |
| 127 | + @ParameterizedTest |
| 128 | + @ValueSource(strings = { |
| 129 | + "SELECT * FROM (SELECT id FROM events) TABLESAMPLE SYSTEM (10 PERCENT)", |
| 130 | + "SELECT * FROM (events) TABLESAMPLE SYSTEM (10 PERCENT)", |
| 131 | + "SELECT * FROM events MATCH_RECOGNIZE (PATTERN (A) DEFINE A AS id > 0) " |
| 132 | + + "TABLESAMPLE SYSTEM (10 PERCENT)" |
| 133 | + }) |
| 134 | + void serializeOtherSampleClauseOwners(String sql) throws Exception { |
| 135 | + PlainSelect original = (PlainSelect) CCJSqlParserUtil.parse(sql); |
| 136 | + PlainSelect copy = roundTrip(original); |
| 137 | + assertSampleClause(new SampleClause("TABLESAMPLE", "SYSTEM", 10L, "PERCENT", null, null), |
| 138 | + copy.getFromItem().getSampleClause()); |
| 139 | + } |
| 140 | + |
| 141 | + @Test |
| 142 | + void serializeSampleClauseAfterMutation() throws Exception { |
| 143 | + PlainSelect original = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed( |
| 144 | + "SELECT * FROM events SAMPLE BLOCK (10) SEED (7)"); |
| 145 | + SampleClause sample = original.getFromItem().getSampleClause(); |
| 146 | + sample.setPercentageArgument(new BigDecimal("12.5")); |
| 147 | + sample.setSeedArgument(new BigDecimal("7.5")); |
| 148 | + PlainSelect copy = roundTrip(original); |
| 149 | + SampleClause copiedSample = copy.getFromItem().getSampleClause(); |
| 150 | + assertSampleClause(new SampleClause("SAMPLE", "BLOCK", new BigDecimal("12.5"), null, |
| 151 | + null, new BigDecimal("7.5")), copiedSample); |
| 152 | + Assertions.assertNotSame(sample, copiedSample); |
| 153 | + sample.setSeedArgument(99L); |
| 154 | + Assertions.assertEquals(new BigDecimal("7.5"), copiedSample.getSeedArgument()); |
| 155 | + } |
| 156 | + |
| 157 | + @ParameterizedTest |
| 158 | + @ValueSource(strings = {"", " ON DELETE CASCADE", " ON DELETE NO ACTION"}) |
| 159 | + void serializeSpannerInterleaveIn(String action) throws Exception { |
| 160 | + CreateTable original = (CreateTable) TestUtils.assertSqlCanBeParsedAndDeparsed( |
| 161 | + "CREATE TABLE child (id INT) PRIMARY KEY (id), INTERLEAVE IN PARENT parent" |
| 162 | + + action); |
| 163 | + CreateTable copy = roundTrip(original); |
| 164 | + SpannerInterleaveIn interleave = copy.getSpannerInterleaveIn(); |
| 165 | + Assertions.assertEquals("parent", interleave.getTable().getName()); |
| 166 | + SpannerInterleaveIn.OnDelete expected = action.isEmpty() ? null |
| 167 | + : action.endsWith("CASCADE") ? SpannerInterleaveIn.OnDelete.CASCADE |
| 168 | + : SpannerInterleaveIn.OnDelete.NO_ACTION; |
| 169 | + Assertions.assertEquals(expected, interleave.getOnDelete()); |
| 170 | + Assertions.assertEquals("child", copy.getTable().getName()); |
| 171 | + Assertions.assertEquals("id", copy.getColumnDefinitions().get(0).getColumnName()); |
| 172 | + Assertions.assertEquals("INT", |
| 173 | + copy.getColumnDefinitions().get(0).getColDataType().getDataType()); |
| 174 | + original.getSpannerInterleaveIn().getTable().setName("changed"); |
| 175 | + Assertions.assertEquals("parent", interleave.getTable().getName()); |
| 176 | + } |
| 177 | + |
| 178 | + @Test |
| 179 | + void serializeCombinedHelpers() throws Exception { |
| 180 | + PlainSelect original = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed( |
| 181 | + "SELECT a.id FROM a TABLESAMPLE SYSTEM (10) INNER LOOP JOIN b " |
| 182 | + + "ON a.id = b.id JOIN c ON b.id = c.id"); |
| 183 | + PlainSelect copy = roundTrip(original); |
| 184 | + Assertions.assertEquals("LOOP", copy.getJoins().get(0).getJoinHint().getKeyword()); |
| 185 | + assertSampleClause(new SampleClause("TABLESAMPLE", "SYSTEM", 10L, null, null, null), |
| 186 | + ((Table) copy.getFromItem()).getSampleClause()); |
| 187 | + Assertions.assertNull(((Table) copy.getJoins().get(0).getFromItem()).getSampleClause()); |
| 188 | + Assertions.assertNull(copy.getJoins().get(1).getJoinHint()); |
| 189 | + Assertions.assertNull(((Table) copy.getJoins().get(1).getFromItem()).getSampleClause()); |
| 190 | + } |
| 191 | + |
| 192 | + @Test |
| 193 | + void serializeSelectWithoutHelpers() throws Exception { |
| 194 | + PlainSelect original = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed( |
| 195 | + "SELECT a.id FROM a INNER JOIN b ON a.id = b.id WHERE b.id > 0"); |
| 196 | + PlainSelect copy = roundTrip(original); |
| 197 | + Assertions.assertNull(copy.getJoins().get(0).getJoinHint()); |
| 198 | + Assertions.assertNull(((Table) copy.getFromItem()).getSampleClause()); |
| 199 | + Assertions.assertEquals("b.id > 0", copy.getWhere().toString()); |
| 200 | + } |
| 201 | + |
| 202 | + @Test |
| 203 | + void serializeCreateTableWithoutInterleave() throws Exception { |
| 204 | + CreateTable original = (CreateTable) TestUtils.assertSqlCanBeParsedAndDeparsed( |
| 205 | + "CREATE TABLE ordinary (id INT)"); |
| 206 | + CreateTable copy = roundTrip(original); |
| 207 | + Assertions.assertNull(copy.getSpannerInterleaveIn()); |
| 208 | + Assertions.assertEquals("ordinary", copy.getTable().getName()); |
| 209 | + Assertions.assertEquals("id", copy.getColumnDefinitions().get(0).getColumnName()); |
| 210 | + } |
| 211 | + |
| 212 | + private static void assertSampleClause(SampleClause expected, SampleClause actual) { |
| 213 | + Assertions.assertNotNull(actual); |
| 214 | + Assertions.assertEquals(expected.getKeyword(), actual.getKeyword()); |
| 215 | + Assertions.assertEquals(expected.getMethod(), actual.getMethod()); |
| 216 | + Assertions.assertEquals(expected.getPercentageArgument(), actual.getPercentageArgument()); |
| 217 | + Assertions.assertEquals(expected.getPercentageUnit(), actual.getPercentageUnit()); |
| 218 | + Assertions.assertEquals(expected.isArgumentInBrackets(), actual.isArgumentInBrackets()); |
| 219 | + Assertions.assertEquals(expected.isMethodInBrackets(), actual.isMethodInBrackets()); |
| 220 | + Assertions.assertEquals(expected.getOffsetArgument(), actual.getOffsetArgument()); |
| 221 | + Assertions.assertEquals(expected.getRepeatArgument(), actual.getRepeatArgument()); |
| 222 | + Assertions.assertEquals(expected.getSeedArgument(), actual.getSeedArgument()); |
| 223 | + } |
| 224 | + |
| 225 | + @SuppressWarnings("unchecked") |
| 226 | + private static <T extends Statement> T roundTrip(T original) |
| 227 | + throws IOException, ClassNotFoundException { |
| 228 | + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); |
| 229 | + try (ObjectOutputStream out = new ObjectOutputStream(bytes)) { |
| 230 | + out.writeObject(original); |
| 231 | + } |
| 232 | + T copy; |
| 233 | + try (ObjectInputStream in = |
| 234 | + new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()))) { |
| 235 | + copy = (T) in.readObject(); |
| 236 | + } |
| 237 | + Assertions.assertNotSame(original, copy); |
| 238 | + Assertions.assertEquals(original.toString(), copy.toString()); |
| 239 | + return copy; |
| 240 | + } |
| 241 | + |
52 | 242 | } |
0 commit comments