001/* 002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the Eclipse Public License v1.0 006 * which accompanies this distribution, and is available at 007 * http://www.eclipse.org/legal/epl-v10.html 008 * 009 * Contributors: 010 * Florent Guillaume 011 */ 012package org.nuxeo.ecm.core.storage.sql.jdbc.db; 013 014import java.io.Serializable; 015import java.util.LinkedList; 016import java.util.List; 017 018import org.nuxeo.ecm.core.storage.sql.jdbc.dialect.Dialect; 019 020/** 021 * A SQL JOIN. 022 */ 023public class Join implements Serializable, Comparable<Join> { 024 025 private static final long serialVersionUID = 1L; 026 027 public static final int INNER = 1; 028 029 public static final int LEFT = 2; 030 031 public static final int RIGHT = 3; 032 033 public static final int IMPLICIT = 4; 034 035 /** INNER / LEFT / RIGHT / IMPLICIT */ 036 public final int kind; 037 038 /** Table name. */ 039 public final String table; 040 041 /** Table alias, or {@code null}. */ 042 public final String tableAlias; 043 044 /** 045 * Parameter if table name is an expression that contains a "?", or {@code null}. 046 */ 047 public final String tableParam; 048 049 /** Left part of equijoin. */ 050 public Column column1; 051 052 /** Right part of equijoin. */ 053 public Column column2; 054 055 /** Left part of equijoin. */ 056 public String on1; 057 058 /** Right part of equijoin. */ 059 public String on2; 060 061 /** Additional WHERE clauses. */ 062 public final List<String> whereClauses = new LinkedList<String>(); 063 064 /** Additional WHERE clauses parameters. */ 065 public final List<Serializable> whereParams = new LinkedList<Serializable>(); 066 067 private Join(int kind, String table, String tableAlias, String tableParam) { 068 this.kind = kind; 069 this.table = table; 070 this.tableAlias = tableAlias; 071 this.tableParam = tableParam; 072 } 073 074 public Join(int kind, String table, String tableAlias, String tableParam, Column column1, Column column2) { 075 this(kind, table, tableAlias, tableParam); 076 this.column1 = column1; 077 this.column2 = column2; 078 } 079 080 public Join(int kind, String table, String tableAlias, String tableParam, String on1, String on2) { 081 this(kind, table, tableAlias, tableParam); 082 this.on1 = on1; 083 this.on2 = on2; 084 } 085 086 public void addWhereClause(String whereClause, Serializable whereParam) { 087 whereClauses.add(whereClause); 088 whereParams.add(whereParam); 089 } 090 091 // make sure IMPLICIT joins are last 092 @Override 093 public int compareTo(Join other) { 094 if (kind == IMPLICIT && other.kind == IMPLICIT) { 095 return 0; 096 } 097 if (kind == IMPLICIT) { 098 return 1; 099 } 100 if (other.kind == IMPLICIT) { 101 return -1; 102 } 103 return 0; 104 } 105 106 public String getTable(Dialect dialect) { 107 if (tableAlias == null) { 108 return table; 109 } else { 110 return table + " " + dialect.openQuote() + tableAlias + dialect.closeQuote(); 111 } 112 } 113 114 public String getClause(Dialect dialect) { 115 if (on1 == null && on2 == null) { 116 on1 = column1.getFullQuotedName(); 117 on2 = column2.getFullQuotedName(); 118 boolean isid1 = column1.getType().isId(); 119 boolean isid2 = column2.getType().isId(); 120 if (dialect != null && isid1 != isid2) { 121 // temporary fix cast uuid to varchar because relation table 122 // has varchar source and target field 123 if (isid1) { 124 on1 = dialect.castIdToVarchar(on1); 125 } else { 126 on2 = dialect.castIdToVarchar(on2); 127 } 128 } 129 } 130 return on1 + " = " + on2; 131 } 132 133 /** 134 * Does not return the WHERE clause. 135 * <p> 136 * {@inheritDoc} 137 */ 138 public String toSql(Dialect dialect) { 139 switch (kind) { 140 case INNER: 141 return String.format(" JOIN %s ON %s", getTable(dialect), getClause(dialect)); 142 case LEFT: 143 return String.format(" LEFT JOIN %s ON %s", getTable(dialect), getClause(dialect)); 144 case RIGHT: 145 return String.format(" RIGHT JOIN %s ON %s", getTable(dialect), getClause(dialect)); 146 case IMPLICIT: 147 return String.format(", %s", getTable(dialect)); 148 default: 149 throw new AssertionError(); 150 } 151 } 152 153 @Override 154 public String toString() { 155 String k; 156 switch (kind) { 157 case INNER: 158 k = "INNER"; 159 break; 160 case LEFT: 161 k = "LEFT"; 162 break; 163 case RIGHT: 164 k = "RIGHT"; 165 break; 166 case IMPLICIT: 167 k = "IMPLICIT"; 168 break; 169 default: 170 throw new AssertionError(); 171 } 172 StringBuilder buf = new StringBuilder(); 173 buf.append("<"); 174 buf.append(k); 175 buf.append(" JOIN "); 176 buf.append(table); 177 if (tableAlias != null) { 178 buf.append(" "); 179 buf.append(tableAlias); 180 } 181 buf.append(" ON "); 182 buf.append(getClause(null)); 183 if (!whereClauses.isEmpty()) { 184 buf.append(" WHERE "); 185 buf.append(whereClauses); 186 buf.append(" % "); 187 buf.append(whereParams); 188 } 189 buf.append(">"); 190 return buf.toString(); 191 } 192 193}