Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -62,22 +62,36 @@ protected IPv4Literal(IPv4Literal other) {
this.value = other.value;
}

private static long parseIPv4toLong(String ipv4) {
String[] parts = ipv4.split("\\.");
private static long parseIPv4toLong(String ipv4) throws AnalysisException {
// Use limit -1 so a trailing dot keeps its empty part: "1.2.3.4." stays 5 parts and is
// rejected by the count check below (plain split("\\.") drops the trailing "" and would
// wrongly yield 4). An IPv4 address must be exactly 4 dot-separated parts.
String[] parts = ipv4.split("\\.", -1);
if (parts.length != 4) {
return 0L;
throw new AnalysisException("Invalid IPv4 format: " + ipv4);
}

long value = 0L;
for (int i = 0; i < 4; ++i) {
short octet;
try {
octet = Short.parseShort(parts[i]);
} catch (NumberFormatException e) {
return 0L;
String part = parts[i];
// Each octet must be 1-3 ASCII digits. Short.parseShort alone is too lax for a DDL
// validator: it accepts a leading '+' and Unicode digits (fullwidth, Arabic-Indic,
// etc.), which BE's ASCII-only parse_ipv4 later rejects, turning the stored default
// into a late failure at load time. So check ASCII digits explicitly here. Leading
// zeros stay decimal ("010" -> 10), consistent with the BE parser and Nereids.
if (part.isEmpty() || part.length() > 3) {
throw new AnalysisException("Invalid IPv4 format: " + ipv4);
}
if (octet < 0 || octet > 255) {
return 0L;
for (int j = 0; j < part.length(); ++j) {
char c = part.charAt(j);
if (c < '0' || c > '9') {
throw new AnalysisException("Invalid IPv4 format: " + ipv4);
}
}
// Safe now: 1-3 ASCII digits never overflow short and never throw.
short octet = Short.parseShort(part);
if (octet > 255) {
throw new AnalysisException("Invalid IPv4 format: " + ipv4);
}
value = (value << 8) | octet;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 org.apache.doris.nereids.trees.expressions.literal;

import org.apache.doris.analysis.ColumnDef;
import org.apache.doris.catalog.Type;
import org.apache.doris.common.AnalysisException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

class IPV4LiteralTest {

@Test
public void testValidIPv4() throws AnalysisException {
new org.apache.doris.analysis.IPv4Literal("0.0.0.0");
new org.apache.doris.analysis.IPv4Literal("192.168.1.1");
new org.apache.doris.analysis.IPv4Literal("255.255.255.255");
new org.apache.doris.analysis.IPv4Literal("10.0.0.1");
// leading zeros are decimal (not octal) and accepted, consistent with the BE
// parser and the Nereids literal: "010.000.000.001" normalizes to the same string as
// "10.0.0.1". Rejecting them here would break already-valid IPv4 defaults.
Assertions.assertEquals(
new org.apache.doris.analysis.IPv4Literal("10.0.0.1").getStringValue(),
new org.apache.doris.analysis.IPv4Literal("010.000.000.001").getStringValue());
new org.apache.doris.analysis.IPv4Literal("010.0.0.1");
}

@Test
public void testInvalidIPv4() {
Assertions.assertThrows(AnalysisException.class,
() -> new org.apache.doris.analysis.IPv4Literal("not_an_ip"));
Assertions.assertThrows(AnalysisException.class,
() -> new org.apache.doris.analysis.IPv4Literal("256.0.0.0"));
Assertions.assertThrows(AnalysisException.class,
() -> new org.apache.doris.analysis.IPv4Literal("999.999.999.999"));
Assertions.assertThrows(AnalysisException.class,
() -> new org.apache.doris.analysis.IPv4Literal("1.2.3"));
Assertions.assertThrows(AnalysisException.class,
() -> new org.apache.doris.analysis.IPv4Literal("1.2.3.4.5"));
Assertions.assertThrows(AnalysisException.class,
() -> new org.apache.doris.analysis.IPv4Literal(""));
// trailing dot / trailing empty octet: split("\\.") used to drop these tokens
Assertions.assertThrows(AnalysisException.class,
() -> new org.apache.doris.analysis.IPv4Literal("1.2.3.4."));
Assertions.assertThrows(AnalysisException.class,
() -> new org.apache.doris.analysis.IPv4Literal("1.2.3.4.."));
// signed octet: Short.parseShort used to accept a leading '+' or '-'
Assertions.assertThrows(AnalysisException.class,
() -> new org.apache.doris.analysis.IPv4Literal("1.2.+3.4"));
Assertions.assertThrows(AnalysisException.class,
() -> new org.apache.doris.analysis.IPv4Literal("1.2.-3.4"));
// leading empty octet and embedded whitespace are rejected
Assertions.assertThrows(AnalysisException.class,
() -> new org.apache.doris.analysis.IPv4Literal(".1.2.3"));
Assertions.assertThrows(AnalysisException.class,
() -> new org.apache.doris.analysis.IPv4Literal("1.2.3. 4"));
// a colon-containing IPv4-mapped IPv6 form must not be accepted as a plain IPv4 literal
Assertions.assertThrows(AnalysisException.class,
() -> new org.apache.doris.analysis.IPv4Literal("::ffff:1.2.3.4"));
// Unicode digits: Short.parseShort and Character.isDigit accept them, but BE's parse_ipv4
// is ASCII-only, so reject them at CREATE TABLE time instead of failing later at load.
Assertions.assertThrows(AnalysisException.class, // fullwidth digits U+FF11.. for "127.0.0.1"
() -> new org.apache.doris.analysis.IPv4Literal("127.0.0.1"));
Assertions.assertThrows(AnalysisException.class, // Arabic-Indic digit U+0663 in 3rd octet
() -> new org.apache.doris.analysis.IPv4Literal("1.2.٣.4"));
}

@Test
public void testValidateDefaultValueIPv4() throws AnalysisException {
ColumnDef.validateDefaultValue(Type.IPV4, "192.168.0.1", null);
ColumnDef.validateDefaultValue(Type.IPV4, "0.0.0.0", null);
ColumnDef.validateDefaultValue(Type.IPV4, "255.255.255.255", null);
}

@Test
public void testValidateDefaultValueIPv4Invalid() {
Assertions.assertThrows(AnalysisException.class,
() -> ColumnDef.validateDefaultValue(Type.IPV4, "not_an_ip", null));
Assertions.assertThrows(AnalysisException.class,
() -> ColumnDef.validateDefaultValue(Type.IPV4, "999.999.999.999", null));
Assertions.assertThrows(AnalysisException.class,
() -> ColumnDef.validateDefaultValue(Type.IPV4, "256.0.0.1", null));
}
}
Loading