Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/sql-ref-ansi-compliance.md
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,7 @@ Below is a list of all the keywords in Spark SQL.
|REGEXP|non-reserved|non-reserved|not a keyword|
|RENAME|non-reserved|non-reserved|non-reserved|
|REPAIR|non-reserved|non-reserved|non-reserved|
|REPEATABLE|non-reserved|non-reserved|non-reserved|
|REPLACE|non-reserved|non-reserved|non-reserved|
|RESET|non-reserved|non-reserved|non-reserved|
|RESPECT|non-reserved|non-reserved|non-reserved|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ joinCriteria
;

sample
: TABLESAMPLE '(' sampleMethod? ')'
: TABLESAMPLE '(' sampleMethod? ')' (REPEATABLE '('seed=INTEGER_VALUE')')?
;

sampleMethod
Expand Down Expand Up @@ -1194,6 +1194,7 @@ ansiNonReserved
| REFRESH
| RENAME
| REPAIR
| REPEATABLE
| REPLACE
| RESET
| RESPECT
Expand Down Expand Up @@ -1460,6 +1461,7 @@ nonReserved
| REFRESH
| RENAME
| REPAIR
| REPEATABLE
| REPLACE
| RESET
| RESPECT
Expand Down Expand Up @@ -1726,6 +1728,7 @@ REFERENCES: 'REFERENCES';
REFRESH: 'REFRESH';
RENAME: 'RENAME';
REPAIR: 'REPAIR';
REPEATABLE: 'REPEATABLE';
REPLACE: 'REPLACE';
RESET: 'RESET';
RESPECT: 'RESPECT';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1180,29 +1180,35 @@ class AstBuilder extends SqlBaseBaseVisitor[AnyRef] with SQLConfHelper with Logg
*/
private def withSample(ctx: SampleContext, query: LogicalPlan): LogicalPlan = withOrigin(ctx) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also update method doc.

// Create a sampled plan if we need one.
def sample(fraction: Double): Sample = {
def sample(fraction: Double, seed: Long): Sample = {
// The range of fraction accepted by Sample is [0, 1]. Because Hive's block sampling
// function takes X PERCENT as the input and the range of X is [0, 100], we need to
// adjust the fraction.
val eps = RandomSampler.roundingEpsilon
validate(fraction >= 0.0 - eps && fraction <= 1.0 + eps,
s"Sampling fraction ($fraction) must be on interval [0, 1]",
ctx)
Sample(0.0, fraction, withReplacement = false, (math.random * 1000).toInt, query)
Sample(0.0, fraction, withReplacement = false, seed, query)
}

if (ctx.sampleMethod() == null) {
throw QueryParsingErrors.emptyInputForTableSampleError(ctx)
}

val seed = if (ctx.seed != null) {
ctx.seed.getText.toLong
} else {
(math.random * 1000).toLong
}

ctx.sampleMethod() match {
case ctx: SampleByRowsContext =>
Limit(expression(ctx.expression), query)

case ctx: SampleByPercentileContext =>
val fraction = ctx.percentage.getText.toDouble
val sign = if (ctx.negativeSign == null) 1 else -1
sample(sign * fraction / 100.0d)
sample(sign * fraction / 100.0d, seed)

case ctx: SampleByBytesContext =>
val bytesStr = ctx.bytes.getText
Expand All @@ -1222,7 +1228,7 @@ class AstBuilder extends SqlBaseBaseVisitor[AnyRef] with SQLConfHelper with Logg
}

case ctx: SampleByBucketContext =>
sample(ctx.numerator.getText.toDouble / ctx.denominator.getText.toDouble)
sample(ctx.numerator.getText.toDouble / ctx.denominator.getText.toDouble, seed)
}
}

Expand Down
16 changes: 16 additions & 0 deletions sql/core/src/test/scala/org/apache/spark/sql/SQLQuerySuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4211,6 +4211,22 @@ class SQLQuerySuite extends QueryTest with SharedSparkSession with AdaptiveSpark
sql("SELECT * FROM testData, LATERAL (SELECT * FROM testData)").collect()
}
}

test("TABLE SAMPLE") {
withTable("test") {
sql("CREATE TABLE test(c int) USING PARQUET")
for( i <- 0 to 20) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: for (i <- 0 to 20)

sql(s"INSERT INTO test VALUES ($i)")
}
val df1 = sql("SELECT * FROM test TABLESAMPLE (20 PERCENT) REPEATABLE (12345)")
val df2 = sql("SELECT * FROM test TABLESAMPLE (20 PERCENT) REPEATABLE (12345)")
checkAnswer(df1, df2)

val df3 = sql("SELECT * FROM test TABLESAMPLE (BUCKET 4 OUT OF 10) REPEATABLE (6789)")
val df4 = sql("SELECT * FROM test TABLESAMPLE (BUCKET 4 OUT OF 10) REPEATABLE (6789)")
checkAnswer(df3, df4)
}
}
}

case class Foo(bar: Option[String])