/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.sql.pg; import com.foundationdb.server.error.UnknownDataTypeException; import com.foundationdb.server.types.TInstance; import com.foundationdb.server.types.common.types.TypesTranslator; import com.foundationdb.sql.optimizer.plan.BasePlannable; import com.foundationdb.sql.optimizer.plan.PhysicalSelect; import com.foundationdb.sql.optimizer.plan.PhysicalUpdate; import com.foundationdb.sql.optimizer.rule.PlanContext; import com.foundationdb.sql.parser.DMLStatementNode; import com.foundationdb.sql.parser.ParameterNode; import com.foundationdb.sql.parser.StatementNode; import com.foundationdb.sql.server.ServerPlanContext; import java.util.List; public abstract class PostgresBaseOperatorStatement extends PostgresDMLStatement { private PostgresOperatorCompiler compiler; protected PostgresBaseOperatorStatement(PostgresOperatorCompiler compiler) { this.compiler = compiler; } @Override public PostgresStatement finishGenerating(PostgresServerSession server, String sql, StatementNode stmt, List<ParameterNode> params, int[] paramTypes) { DMLStatementNode dmlStmt = (DMLStatementNode)stmt; PostgresQueryContext queryContext = new PostgresQueryContext(server); PlanContext planContext = new ServerPlanContext(compiler, queryContext); // TODO: This needs to make types with better default attributes or else // decimals and strings get truncated, collation doesn't match, etc. if (paramTypes != null && false) { for (ParameterNode param : params) { int paramno = param.getParameterNumber(); if (paramno < paramTypes.length) { TInstance type = null; try { type = server.typesTranslator().typeClassForJDBCType(PostgresType.toJDBC(paramTypes[paramno])).instance(true); } catch (UnknownDataTypeException ex) { server.warnClient(ex); } param.setUserData(type); } } } BasePlannable result = compiler.compile(dmlStmt, params, planContext); PostgresType[] parameterTypes = getParameterTypes(result.getParameterTypes(), paramTypes, server.typesTranslator()); final PostgresBaseOperatorStatement pbos; if (result.isUpdate()) pbos = compiler.generateUpdate(this, (PhysicalUpdate)result, stmt.statementToString(), parameterTypes); else pbos = compiler.generateSelect(this, (PhysicalSelect)result, parameterTypes); pbos.compiler = null; return pbos; } protected PostgresType[] getParameterTypes(BasePlannable.ParameterType[] planTypes, int[] paramTypes, TypesTranslator typesTranslator) { if (planTypes == null) return null; int nparams = planTypes.length; PostgresType[] parameterTypes = new PostgresType[nparams]; for (int i = 0; i < nparams; i++) { BasePlannable.ParameterType planType = planTypes[i]; PostgresType pgType = null; if ((planType != null) && (planType.getType() != null)) { pgType = PostgresType.fromTInstance(planType.getType()); } if ((paramTypes != null) && (i < paramTypes.length)) { // Make a type that has the target that the query wants, with the // OID that the client proposed to send so that we // decode it properly. PostgresType.TypeOid oid = PostgresType.TypeOid.fromOid(paramTypes[i]); if (oid != null) { if (pgType == null) pgType = new PostgresType(oid, (short)-1, -1, null); else pgType = new PostgresType(oid, (short)-1, -1, pgType.getType()); } } parameterTypes[i] = pgType; } return parameterTypes; } }