1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.hadoop.hbase.hbql.statement;
22
23 import org.apache.hadoop.hbase.hbql.client.HBqlException;
24 import org.apache.hadoop.hbase.hbql.impl.HConnectionImpl;
25 import org.apache.hadoop.hbase.hbql.impl.InvalidColumnException;
26 import org.apache.hadoop.hbase.hbql.mapping.ColumnAttrib;
27 import org.apache.hadoop.hbase.hbql.statement.args.WithArgs;
28 import org.apache.hadoop.hbase.hbql.statement.select.SelectElement;
29 import org.apache.hadoop.hbase.hbql.util.Lists;
30 import org.apache.hadoop.hbase.hbql.util.Sets;
31
32 import java.util.List;
33 import java.util.Set;
34 import java.util.concurrent.atomic.AtomicInteger;
35
36 public class SelectStatement extends StatementWithParameters implements HBqlStatement {
37
38 private final List<ColumnAttrib> selectColumnAttribList = Lists.newArrayList();
39 private final AtomicInteger expressionCounter = new AtomicInteger(-1);
40 private final List<SelectElement> selectElementList;
41 private final WithArgs withArgs;
42
43 private boolean validated = false;
44 private boolean aggregateQuery = false;
45
46 public SelectStatement(final List<SelectElement> selectElementList,
47 final String mappingName,
48 final WithArgs withArgs) {
49 super(null, mappingName);
50 this.selectElementList = selectElementList;
51 this.withArgs = withArgs != null ? withArgs : new WithArgs();
52 }
53
54 public synchronized String getNextExpressionName() {
55 return "expr-" + this.expressionCounter.incrementAndGet();
56 }
57
58 private boolean isValidated() {
59 return this.validated;
60 }
61
62 public List<SelectElement> getSelectElementList() {
63 return this.selectElementList;
64 }
65
66 public List<ColumnAttrib> getSelectAttribList() {
67 return this.selectColumnAttribList;
68 }
69
70 public WithArgs getWithArgs() {
71 return this.withArgs;
72 }
73
74 public synchronized void validate(final HConnectionImpl conn) throws HBqlException {
75
76 if (this.isValidated())
77 return;
78
79 this.validated = true;
80
81 this.getMappingContext().validateMappingName(conn);
82
83 this.getSelectAttribList().clear();
84
85 for (final SelectElement element : this.getSelectElementList()) {
86 element.validate(this.getMappingContext(), conn);
87 element.assignAsNamesForExpressions(this);
88 this.getSelectAttribList().addAll(element.getAttribsUsedInExpr());
89 }
90
91 this.getWithArgs().setMappingContext(this.getMappingContext());
92 this.getWithArgs().validate(conn, this.getMappingContext().getTableMapping());
93
94
95 this.checkForDuplicateAsNames();
96
97
98 this.collectParameters();
99 }
100
101 public void validateTypes() throws HBqlException {
102 this.getWithArgs().validateArgTypes();
103 }
104
105 public void determineIfAggregateQuery() throws HBqlException {
106
107
108 for (final SelectElement element : this.getSelectElementList()) {
109 try {
110 element.validateTypes(true, false);
111 }
112 catch (InvalidColumnException e) {
113
114 e.printStackTrace();
115 }
116 }
117
118 this.aggregateQuery = this.checkIfAggregateQuery();
119 }
120
121 private boolean checkIfAggregateQuery() throws HBqlException {
122 final SelectElement firstElement = this.getSelectElementList().get(0);
123 final boolean firstIsAggregate = firstElement.isAnAggregateElement();
124 for (final SelectElement selectElement : this.getSelectElementList()) {
125 if (selectElement.isAnAggregateElement() != firstIsAggregate)
126 throw new HBqlException("Cannot mix aggregate and non-aggregate select elements");
127 }
128 return firstIsAggregate;
129 }
130
131 public boolean isAnAggregateQuery() {
132 return this.aggregateQuery;
133 }
134
135 private void checkForDuplicateAsNames() throws HBqlException {
136 final Set<String> asNameSet = Sets.newHashSet();
137 for (final SelectElement selectElement : this.getSelectElementList()) {
138 if (selectElement.hasAsName()) {
139 final String asName = selectElement.getAsName();
140 if (asNameSet.contains(asName))
141 throw new HBqlException("Duplicate select name " + asName + " in select list");
142 asNameSet.add(asName);
143 }
144 }
145 }
146
147 public boolean hasAsName(final String name) {
148 for (final SelectElement selectElement : this.getSelectElementList())
149 if (selectElement.hasAsName() && selectElement.getAsName().equals(name))
150 return true;
151 return false;
152 }
153
154 private void collectParameters() {
155 for (final SelectElement selectElement : this.getSelectElementList())
156 this.getNamedParameters().addParameters(selectElement.getParameterList());
157
158 this.getNamedParameters().addParameters(this.getWithArgs().getParameterList());
159 }
160
161 public void resetParameters() {
162 for (final SelectElement selectElement : this.getSelectElementList())
163 selectElement.reset();
164
165 this.getWithArgs().reset();
166 }
167
168
169 public int setStatementParameter(final String name, final Object val) throws HBqlException {
170 int cnt = 0;
171 for (final SelectElement selectElement : this.getSelectElementList())
172 cnt += selectElement.setParameter(name, val);
173
174 cnt += this.getWithArgs().setParameter(name, val);
175 return cnt;
176 }
177
178 public String asString() {
179 final StringBuilder sbuf = new StringBuilder("SELECT ");
180 boolean firstTime = true;
181 for (final SelectElement element : this.getSelectElementList()) {
182 if (!firstTime)
183 sbuf.append(", ");
184 firstTime = false;
185
186 sbuf.append(element.asString());
187 }
188
189 sbuf.append(" FROM ");
190 sbuf.append(this.getMappingContext().getMappingName());
191 sbuf.append(" ");
192 sbuf.append(this.getWithArgs().asString());
193 return sbuf.toString();
194 }
195
196 public static String usage() {
197 return "SELECT select_element_list FROM [MAPPING] mapping_name with_clause";
198 }
199 }