/** * 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.hadoop.hive.contrib.genericudf.example; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.hadoop.hive.ql.exec.Description; import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException; import org.apache.hadoop.hive.ql.metadata.HiveException; import org.apache.hadoop.hive.ql.udf.UDFType; import org.apache.hadoop.hive.ql.udf.generic.GenericUDF; import org.apache.hadoop.hive.serde.serdeConstants; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory; import org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector; import org.apache.hadoop.io.IntWritable; /** * GenericUDFDBOutput is designed to output data directly from Hive to a JDBC * datastore. This UDF is useful for exporting small to medium summaries that * have a unique key. * * Due to the nature of hadoop, individual mappers, reducers or entire jobs can * fail. If a failure occurs a mapper or reducer may be retried. This UDF has no * way of detecting failures or rolling back a transaction. Consequently, you * should only only use this to export to a table with a unique key. The unique * key should safeguard against duplicate data. * * Use hive's ADD JAR feature to add your JDBC Driver to the distributed cache, * otherwise GenericUDFDBoutput will fail. */ @Description(name = "dboutput", value = "_FUNC_(jdbcstring,username,password,preparedstatement,[arguments])" + " - sends data to a jdbc driver", extended = "argument 0 is the JDBC connection string\n" + "argument 1 is the user name\n" + "argument 2 is the password\n" + "argument 3 is an SQL query to be used in the PreparedStatement\n" + "argument (4-n) The remaining arguments must be primitive and are " + "passed to the PreparedStatement object\n") @UDFType(deterministic = false) public class GenericUDFDBOutput extends GenericUDF { private static final Logger LOG = LoggerFactory .getLogger(GenericUDFDBOutput.class.getName()); private transient ObjectInspector[] argumentOI; private transient Connection connection = null; private String url; private String user; private String pass; private final IntWritable result = new IntWritable(-1); /** * @param arguments * argument 0 is the JDBC connection string argument 1 is the user * name argument 2 is the password argument 3 is an SQL query to be * used in the PreparedStatement argument (4-n) The remaining * arguments must be primitive and are passed to the * PreparedStatement object */ @Override public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentTypeException { argumentOI = arguments; // this should be connection url,username,password,query,column1[,columnn]* for (int i = 0; i < 4; i++) { if (arguments[i].getCategory() == ObjectInspector.Category.PRIMITIVE) { PrimitiveObjectInspector poi = ((PrimitiveObjectInspector) arguments[i]); if (!(poi.getPrimitiveCategory() == PrimitiveObjectInspector.PrimitiveCategory.STRING)) { throw new UDFArgumentTypeException(i, "The argument of function should be \"" + serdeConstants.STRING_TYPE_NAME + "\", but \"" + arguments[i].getTypeName() + "\" is found"); } } } for (int i = 4; i < arguments.length; i++) { if (arguments[i].getCategory() != ObjectInspector.Category.PRIMITIVE) { throw new UDFArgumentTypeException(i, "The argument of function should be primative" + ", but \"" + arguments[i].getTypeName() + "\" is found"); } } return PrimitiveObjectInspectorFactory.writableIntObjectInspector; } /** * @return 0 on success -1 on failure */ @Override public Object evaluate(DeferredObject[] arguments) throws HiveException { url = ((StringObjectInspector) argumentOI[0]) .getPrimitiveJavaObject(arguments[0].get()); user = ((StringObjectInspector) argumentOI[1]) .getPrimitiveJavaObject(arguments[1].get()); pass = ((StringObjectInspector) argumentOI[2]) .getPrimitiveJavaObject(arguments[2].get()); try { connection = DriverManager.getConnection(url, user, pass); } catch (SQLException ex) { LOG.error("Driver loading or connection issue", ex); result.set(2); } if (connection != null) { try { PreparedStatement ps = connection .prepareStatement(((StringObjectInspector) argumentOI[3]) .getPrimitiveJavaObject(arguments[3].get())); for (int i = 4; i < arguments.length; ++i) { PrimitiveObjectInspector poi = ((PrimitiveObjectInspector) argumentOI[i]); ps.setObject(i - 3, poi.getPrimitiveJavaObject(arguments[i].get())); } ps.execute(); ps.close(); result.set(0); } catch (SQLException e) { LOG.error("Underlying SQL exception", e); result.set(1); } finally { try { connection.close(); } catch (Exception ex) { LOG.error("Underlying SQL exception during close", ex); } } } return result; } @Override public String getDisplayString(String[] children) { return getStandardDisplayString("dboutput", children, ","); } }