content: /*****************************************************************
   * 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
   * <p/>
   * https://www.apache.org/licenses/LICENSE-2.0
   * <p/>
   * 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.cayenne.dba.ingres;
  
  import org.apache.cayenne.CayenneRuntimeException;
  import org.apache.cayenne.access.DataNode;
  import org.apache.cayenne.access.sqlbuilder.sqltree.SQLTreeProcessor;
  import org.apache.cayenne.access.translator.ParameterBinding;
  import org.apache.cayenne.access.types.ExtendedType;
  import org.apache.cayenne.access.types.ExtendedTypeFactory;
  import org.apache.cayenne.access.types.ExtendedTypeMap;
  import org.apache.cayenne.access.types.ValueObjectTypeRegistry;
  import org.apache.cayenne.configuration.Constants;
  import org.apache.cayenne.configuration.RuntimeProperties;
  import org.apache.cayenne.dba.JdbcAdapter;
  import org.apache.cayenne.dba.PkGenerator;
  import org.apache.cayenne.dba.TypesMapping;
  import org.apache.cayenne.di.Inject;
  import org.apache.cayenne.map.DbAttribute;
  import org.apache.cayenne.query.Query;
  import org.apache.cayenne.query.SQLAction;
  import org.apache.cayenne.resource.ResourceLocator;
  
  import java.sql.PreparedStatement;
  import java.sql.SQLException;
  import java.sql.Types;
  import java.util.List;
  
  /**
   * DbAdapter implementation for <a
   * href="http://opensource.ca.com/projects/ingres/">Ingres</a>. Sample
   * connection settings to use with Ingres are shown below:
   *
   * <pre>
   *  ingres.jdbc.username = test
   *  ingres.jdbc.password = secret
   *  ingres.jdbc.url = jdbc:ingres://serverhostname:II7/cayenne
   *  ingres.jdbc.driver = ca.ingres.jdbc.IngresDriver
   * </pre>
   */
  public class IngresAdapter extends JdbcAdapter {
  
  	public static final String TRIM_FUNCTION = "TRIM";
  
  	public IngresAdapter(@Inject RuntimeProperties runtimeProperties,
  	                     @Inject(Constants.DEFAULT_TYPES_LIST) List<ExtendedType> defaultExtendedTypes,
  	                     @Inject(Constants.USER_TYPES_LIST) List<ExtendedType> userExtendedTypes,
  	                     @Inject(Constants.TYPE_FACTORIES_LIST) List<ExtendedTypeFactory> extendedTypeFactories,
  	                     @Inject(Constants.RESOURCE_LOCATOR) ResourceLocator resourceLocator,
  						 @Inject ValueObjectTypeRegistry valueObjectTypeRegistry) {
  		super(runtimeProperties, defaultExtendedTypes, userExtendedTypes, extendedTypeFactories, resourceLocator, valueObjectTypeRegistry);
  		setSupportsUniqueConstraints(true);
  		setSupportsGeneratedKeys(true);
  	}
  
      /**
       * @since 4.2
       */
  	@Override
  	public SQLTreeProcessor getSqlTreeProcessor() {
  		return new IngressSQLTreeProcessor();
  	}
  
  	@Override
  	public SQLAction getAction(Query query, DataNode node) {
  		return query.createSQLAction(new IngresActionBuilder(node));
  	}
  
  	@Override
  	protected void configureExtendedTypes(ExtendedTypeMap map) {
  		super.configureExtendedTypes(map);
  		map.registerType(new IngresCharType());
  
  		// configure boolean type to work with numeric columns
  		map.registerType(new IngresBooleanType());
  	}
  
  	@Override
  	public void bindParameter(PreparedStatement statement, ParameterBinding binding)
  			throws SQLException, Exception {
  
  		if (binding.getValue() == null && (binding.getJdbcType() == Types.BIT)) {
  			statement.setNull(binding.getStatementPosition(), Types.SMALLINT);
  		} else {
  			super.bindParameter(statement, binding);
  		}
  	}
  
  	@Override
  	public void createTableAppendColumn(StringBuffer buf, DbAttribute at) {
  		String type = getType(this, at);
  		buf.append(quotingStrategy.quotedName(at)).append(' ').append(type);
  
  		// append size and precision (if applicable)
  		if (typeSupportsLength(at.getType())) {
  			int len = at.getMaxLength();
  			int scale = TypesMapping.isDecimal(at.getType()) ? at.getScale() : -1;
  
  			// sanity check
  			if (scale > len) {
  				scale = -1;
  			}
  
  			if (len > 0) {
  				buf.append('(').append(len);
  
  				if (scale >= 0) {
  					buf.append(", ").append(scale);
  				}
  
  				buf.append(')');
  			}
  		}
  
  		if (at.isGenerated()) {
  			buf.append(" GENERATED BY DEFAULT AS IDENTITY ");
  		}
  
  		// Ingres does not like "null" for non mandatory fields
  		if (at.isMandatory()) {
  			buf.append(" NOT NULL");
  		}
  	}
  }
  