/** * 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 com.huawei.streaming.datasource; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.huawei.streaming.exception.StreamingException; import com.huawei.streaming.util.StreamingUtils; /** * 使用JDBC PreparedStatement的数据库数据源算子 * 因为原有的Statement方法可能存在SQL注入风险 * 但是有的数据库没有实现PreparedStatement方法, * 所以还是保留原来Statement的实现 * */ public class PreStatementRDBDataSource extends RDBDataSource { private static final Logger LOG = LoggerFactory.getLogger(PreStatementRDBDataSource.class); private static final long serialVersionUID = 1049038073912137943L; private transient PreparedStatement preStatement; /** * {@inheritDoc} */ @Override public List<Object[]> execute(List<Object> replacedQueryArguments) throws StreamingException { validateQueryArguments(replacedQueryArguments); ResultSet result = null; try { createStatementIfNotExists(replacedQueryArguments); setStatementParameters(replacedQueryArguments); result = preStatement.executeQuery(); return parseQueryResults(result); } catch (SQLException e) { preStatement = null; LOG.error("failed to execute sql query.", e); throw new StreamingException("failed to execute sql query.", e); } finally { StreamingUtils.close(result); } } /** * {@inheritDoc} */ @Override public void destroy() throws StreamingException { LOG.info("Start to close prepare statement."); StreamingUtils.close(preStatement); LOG.info("Success to close prepare statement."); super.destroy(); } private void setStatementParameters(List< Object > replacedQueryArguments) throws SQLException, StreamingException { preStatement.clearParameters(); LOG.debug("Start to set prepare statement parameters."); if (replacedQueryArguments.size() <= 1) { LOG.debug("Can not found replaced query arguments, does not need to set prepare statement parameters."); return; } for (int i = 1; i < replacedQueryArguments.size(); i++) { validateNullQueryParameters(replacedQueryArguments.get(i)); preStatement.setObject(i, replacedQueryArguments.get(i)); } LOG.debug("Success to set prepare statement parameters."); } private void validateNullQueryParameters(Object replacedQueryArgument) throws StreamingException { if (replacedQueryArgument == null) { LOG.error("Null argument is not allowed in RDBDataSource."); throw new StreamingException("Null argument is not allowed in RDBDataSource."); } } private void createStatementIfNotExists(List< Object > replacedQueryArguments) throws SQLException { if (preStatement != null) { return; } LOG.info("Start to create prepare statement."); preStatement = getConnection().prepareStatement(replacedQueryArguments.get(0).toString()); LOG.info("Success to create prepare statement."); } private void validateQueryArguments(List< Object > replacedQueryArguments) throws StreamingException { if (replacedQueryArguments == null || replacedQueryArguments.size() < 0) { LOG.error("Query arguments in RDBDataSource can not be null."); throw new StreamingException("Query arguments in RDBDataSource can not be null."); } if (replacedQueryArguments.get(0) == null) { LOG.error("Query sql in RDBDataSource can not be null."); throw new StreamingException("Query sql in RDBDataSource can not be null."); } } }