Skip to content
Open
Show file tree
Hide file tree
Changes from 12 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
@@ -0,0 +1,43 @@
/*
* 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.shardingsphere.database.connector.core.statement;

import java.sql.SQLException;
import java.sql.PreparedStatement;

/**
* Default prepared statement parameter replayer.
* Keeps the original ShardingSphere behavior: use setObject for all parameters.
*/
public final class DefaultPreparedStatementParameterReplayer implements DialectPreparedStatementParameterReplayer {

@Override
public void replay(final PreparedStatement preparedStatement, final PreparedStatementParameter parameter) throws SQLException {
preparedStatement.setObject(parameter.getIndex(), parameter.getValue());
}

@Override
public String getDatabaseType() {
return null;
}

@Override
public boolean isDefault() {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* 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.shardingsphere.database.connector.core.statement;

import org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPI;
import org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;

import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
* Dialect prepared statement parameter replayer.
* SPI for replaying parameters on PreparedStatement with database-specific handling.
*/
@SingletonSPI
public interface DialectPreparedStatementParameterReplayer extends DatabaseTypedSPI {

/**
* Replay parameter on prepared statement.
*
* @param preparedStatement target prepared statement
* @param parameter parameter to replay
* @throws SQLException SQL exception
*/
void replay(PreparedStatement preparedStatement, PreparedStatementParameter parameter) throws SQLException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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.shardingsphere.database.connector.core.statement;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

/**
* Prepared statement parameter.
* Records the original setter method and its arguments for replay.
*/
@RequiredArgsConstructor
@Getter
public final class PreparedStatementParameter {

private final int index;

private final SetterMethodType setterMethodType;

private final Object value;

private final long length;

public PreparedStatementParameter(final int index, final SetterMethodType setterMethodType, final Object value) {
this(index, setterMethodType, value, -1L);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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.shardingsphere.database.connector.core.statement;

/**
* Setter method type for prepared statement parameters.
*/
public enum SetterMethodType {

SET_OBJECT,

SET_NULL,

SET_BLOB,

SET_BLOB_INPUT_STREAM,

SET_CLOB,

SET_CLOB_READER,

SET_BINARY_STREAM,

SET_ASCII_STREAM,

SET_CHARACTER_STREAM,

SET_BYTES
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#
# 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.
#

org.apache.shardingsphere.database.connector.core.statement.DefaultPreparedStatementParameterReplayer
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* 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.shardingsphere.database.connector.core.statement;

import org.junit.jupiter.api.Test;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

class DefaultPreparedStatementParameterReplayerTest {

private final DefaultPreparedStatementParameterReplayer replayer = new DefaultPreparedStatementParameterReplayer();

@Test
void assertReplayWithSetObject() throws SQLException {
PreparedStatement preparedStatement = mock(PreparedStatement.class);
PreparedStatementParameter parameter = new PreparedStatementParameter(1, SetterMethodType.SET_OBJECT, "testValue", -1);

replayer.replay(preparedStatement, parameter);

verify(preparedStatement).setObject(1, "testValue");
}

@Test
void assertReplayWithSetNull() throws SQLException {
PreparedStatement preparedStatement = mock(PreparedStatement.class);
PreparedStatementParameter parameter = new PreparedStatementParameter(1, SetterMethodType.SET_NULL, null, -1);

replayer.replay(preparedStatement, parameter);

verify(preparedStatement).setObject(1, null);
}

@Test
void assertReplayWithInputStream() throws SQLException {
PreparedStatement preparedStatement = mock(PreparedStatement.class);
InputStream inputStream = new ByteArrayInputStream(new byte[]{1, 2, 3});
PreparedStatementParameter parameter = new PreparedStatementParameter(1, SetterMethodType.SET_BINARY_STREAM, inputStream, -1);

replayer.replay(preparedStatement, parameter);

verify(preparedStatement).setObject(1, inputStream);
}

@Test
void assertReplayWithBlobInputStream() throws SQLException {
PreparedStatement preparedStatement = mock(PreparedStatement.class);
InputStream inputStream = new ByteArrayInputStream(new byte[]{1, 2, 3});
PreparedStatementParameter parameter = new PreparedStatementParameter(1, SetterMethodType.SET_BLOB_INPUT_STREAM, inputStream, 3);

replayer.replay(preparedStatement, parameter);

verify(preparedStatement).setObject(1, inputStream);
}

@Test
void assertGetDatabaseType() {
assertThat(replayer.getDatabaseType(), is(nullValue()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* 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.shardingsphere.database.connector.oracle.statement;

import org.apache.shardingsphere.database.connector.core.statement.DialectPreparedStatementParameterReplayer;
import org.apache.shardingsphere.database.connector.core.statement.PreparedStatementParameter;
import java.io.InputStream;
import java.io.Reader;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
* Oracle prepared statement parameter replayer.
* Handles Oracle-specific BLOB/InputStream parameter issues with ojdbc.
*/
public final class OraclePreparedStatementParameterReplayer implements DialectPreparedStatementParameterReplayer {

@Override
public void replay(final PreparedStatement preparedStatement, final PreparedStatementParameter parameter) throws SQLException {
int index = parameter.getIndex();
Object value = parameter.getValue();
long length = parameter.getLength();

switch (parameter.getSetterMethodType()) {
case SET_NULL:
preparedStatement.setObject(index, null);
break;
case SET_BLOB:
preparedStatement.setBlob(index, (Blob) value);
break;
case SET_CLOB:
preparedStatement.setClob(index, (Clob) value);
break;
case SET_CLOB_READER:
replayClob(preparedStatement, index, (Reader) value, length);
break;
case SET_BLOB_INPUT_STREAM:
replayBlobInputStream(preparedStatement, index, (InputStream) value, length);
break;
case SET_BINARY_STREAM:
replayBinaryStream(preparedStatement, index, (InputStream) value, length);
break;
case SET_ASCII_STREAM:
replayAsciiStream(preparedStatement, index, (InputStream) value, length);
break;
case SET_CHARACTER_STREAM:
replayCharacterStream(preparedStatement, index, (Reader) value, length);
break;
case SET_BYTES:
preparedStatement.setBytes(index, (byte[]) value);
break;
default:
preparedStatement.setObject(index, value);
}
}

private void replayBlobInputStream(final PreparedStatement preparedStatement, final int index, final InputStream value, final long length) throws SQLException {
if (length > 0) {
preparedStatement.setBlob(index, value, length);
} else {
preparedStatement.setBlob(index, value);
}
}

private void replayBinaryStream(final PreparedStatement preparedStatement, final int index, final InputStream value, final long length) throws SQLException {
if (length > 0) {
preparedStatement.setBinaryStream(index, value, length);
} else {
preparedStatement.setBinaryStream(index, value);
}
}

private void replayClob(final PreparedStatement preparedStatement, final int index, final Reader value, final long length) throws SQLException {
if (length > 0) {
preparedStatement.setClob(index, value, length);
} else {
preparedStatement.setClob(index, value);
}
}

private void replayAsciiStream(final PreparedStatement preparedStatement, final int index, final InputStream value, final long length) throws SQLException {
if (length > 0) {
preparedStatement.setAsciiStream(index, value, length);
} else {
preparedStatement.setAsciiStream(index, value);
}
}

private void replayCharacterStream(final PreparedStatement preparedStatement, final int index, final Reader value, final long length) throws SQLException {
if (length > 0) {
preparedStatement.setCharacterStream(index, value, length);
} else {
preparedStatement.setCharacterStream(index, value);
}
}

@Override
public String getDatabaseType() {
return "Oracle";
}
}
Loading