Skip to content

Commit

Permalink
Add luhn_check function
Browse files Browse the repository at this point in the history
  • Loading branch information
urbanfletch authored and electrum committed Jul 27, 2020
1 parent 7f621cc commit 913d42f
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 0 deletions.
5 changes: 5 additions & 0 deletions presto-docs/src/main/sphinx/functions/string.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ String Functions

Removes leading whitespace from ``string``.

.. function:: luhn_check(string) -> boolean

Tests whether a ``string`` of digits is valid according to the
`Luhn algorithm <https://en.wikipedia.org/wiki/Luhn_algorithm>`_.

.. function:: position(substring IN string) -> bigint

Returns the starting position of the first instance of ``substring`` in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
import io.prestosql.operator.scalar.JoniRegexpReplaceLambdaFunction;
import io.prestosql.operator.scalar.JsonFunctions;
import io.prestosql.operator.scalar.JsonOperators;
import io.prestosql.operator.scalar.LuhnCheckFunction;
import io.prestosql.operator.scalar.MapCardinalityFunction;
import io.prestosql.operator.scalar.MapDistinctFromOperator;
import io.prestosql.operator.scalar.MapEntriesFunction;
Expand Down Expand Up @@ -537,6 +538,7 @@ public FunctionRegistry(Metadata metadata, FeaturesConfig featuresConfig)
.scalars(JoniRegexpCasts.class)
.scalars(CharacterStringCasts.class)
.scalars(CharOperators.class)
.scalars(LuhnCheckFunction.class)
.scalar(CharOperators.CharDistinctFromOperator.class)
.scalar(DecimalOperators.Negation.class)
.scalar(DecimalOperators.HashCode.class)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.prestosql.operator.scalar;

import io.airlift.slice.Slice;
import io.prestosql.spi.function.Description;
import io.prestosql.spi.function.ScalarFunction;
import io.prestosql.spi.function.SqlType;
import io.prestosql.spi.type.StandardTypes;

import static io.prestosql.spi.StandardErrorCode.INVALID_FUNCTION_ARGUMENT;
import static io.prestosql.util.Failures.checkCondition;

public final class LuhnCheckFunction
{
private LuhnCheckFunction() {}

@Description("Checks that a string of digits is valid according to the Luhn algorithm")
@ScalarFunction("luhn_check")
@SqlType(StandardTypes.BOOLEAN)
public static boolean LuhnCheck(@SqlType(StandardTypes.VARCHAR) Slice slice)
{
if (slice.length() == 0) {
return false;
}

int nDigits = slice.length();
int sum = 0;
boolean secondNumber = false;

for (int i = nDigits - 1; i >= 0; i--) {
byte b = slice.getByte(i);
checkCondition(b >= '0' && b <= '9', INVALID_FUNCTION_ARGUMENT, "Input contains non-digit character");
int n = b - '0';

// starting from the right double the value of every other number
if (secondNumber) {
n *= 2;
}

// if the value is greater than 9 subtract 9 from n
if (n > 9) {
n -= 9;
}

// add to sum
sum += n;

// update second number check
secondNumber = !secondNumber;
}
//check returns true if mod 10 is zero
return (sum % 10 == 0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.prestosql.operator.scalar;

import org.testng.annotations.Test;

import static io.prestosql.spi.StandardErrorCode.INVALID_FUNCTION_ARGUMENT;
import static io.prestosql.spi.type.BooleanType.BOOLEAN;

public class TestLuhnCheckFunction
extends AbstractTestFunctions
{
@Test
public void testLuhnCheck()
{
assertFunction("luhn_check('4242424242424242')", BOOLEAN, true);
assertFunction("luhn_check('1234567891234567')", BOOLEAN, false);
assertFunction("luhn_check('')", BOOLEAN, false);
assertFunction("luhn_check(NULL)", BOOLEAN, null);
assertInvalidFunction("luhn_check('abcd424242424242')", INVALID_FUNCTION_ARGUMENT);
assertFunction("luhn_check('123456789')", BOOLEAN, false);
assertInvalidFunction("luhn_check('\u4EA0\u4EFF\u4EA112345')", INVALID_FUNCTION_ARGUMENT);
assertInvalidFunction("luhn_check('4242\u4FE124242424242')", INVALID_FUNCTION_ARGUMENT);
}
}

0 comments on commit 913d42f

Please sign in to comment.