View Javadoc

1   /*
2    * Copyright (c) 2011.  The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.hbql.statement;
22  
23  import org.apache.expreval.client.NullColumnValueException;
24  import org.apache.expreval.client.ResultMissingColumnException;
25  import org.apache.expreval.expr.ExpressionTree;
26  import org.apache.hadoop.hbase.client.Delete;
27  import org.apache.hadoop.hbase.client.HTableInterface;
28  import org.apache.hadoop.hbase.client.Result;
29  import org.apache.hadoop.hbase.client.ResultScanner;
30  import org.apache.hadoop.hbase.hbql.client.ExecutionResults;
31  import org.apache.hadoop.hbase.hbql.client.HBqlException;
32  import org.apache.hadoop.hbase.hbql.impl.HConnectionImpl;
33  import org.apache.hadoop.hbase.hbql.impl.HTableWrapper;
34  import org.apache.hadoop.hbase.hbql.mapping.ColumnAttrib;
35  import org.apache.hadoop.hbase.hbql.mapping.TableMapping;
36  import org.apache.hadoop.hbase.hbql.statement.args.WithArgs;
37  import org.apache.hadoop.hbase.hbql.statement.select.RowRequest;
38  import org.apache.hadoop.hbase.hbql.util.Lists;
39  
40  import java.io.IOException;
41  import java.util.List;
42  import java.util.Set;
43  
44  public class DeleteStatement extends StatementWithParameters implements ConnectionStatement {
45  
46      private final List<String> deleteItemList = Lists.newArrayList();
47      private final List<String> originaltemList;
48      private final WithArgs     withArgs;
49  
50      private HConnectionImpl connection = null;
51      private boolean         validated  = false;
52  
53      public DeleteStatement(final StatementPredicate predicate,
54                             final List<String> originaltemList,
55                             final String mappingName,
56                             final WithArgs withArgs) {
57          super(predicate, mappingName);
58  
59          this.withArgs = (withArgs == null) ? new WithArgs() : withArgs;
60  
61          if (originaltemList == null)
62              this.originaltemList = Lists.newArrayList();
63          else
64              this.originaltemList = originaltemList;
65      }
66  
67      private WithArgs getWithArgs() {
68          return this.withArgs;
69      }
70  
71      private List<String> getDeleteItemList() {
72          return this.deleteItemList;
73      }
74  
75      private HConnectionImpl getConnection() {
76          return this.connection;
77      }
78  
79      private boolean isValidated() {
80          return this.validated;
81      }
82  
83      public void validate(final HConnectionImpl conn) throws HBqlException {
84  
85          if (this.isValidated())
86              return;
87  
88          this.validated = true;
89          this.connection = conn;
90  
91          this.getMappingContext().validateMappingName(conn);
92  
93          this.getWithArgs().setMappingContext(this.getMappingContext());
94          this.getWithArgs().validate(conn, this.getMappingContext().getTableMapping());
95  
96          this.collectParameters();
97  
98          // Verify and lookup alias references
99          // Build list with family wildcar refs and family qualified column names
100         for (final String deleteItem : this.originaltemList) {
101             if (deleteItem.contains(":")) {
102                 this.getDeleteItemList().add(deleteItem);
103             }
104             else {
105                 final TableMapping mapping = this.getMappingContext().getTableMapping();
106                 final ColumnAttrib attrib = mapping.getAttribByVariableName(deleteItem);
107                 if (attrib == null)
108                     throw new HBqlException("Invalid variable: " + deleteItem);
109 
110                 this.getDeleteItemList().add(attrib.getFamilyQualifiedName());
111             }
112         }
113     }
114 
115     public void validateTypes() throws HBqlException {
116         this.getWithArgs().validateArgTypes();
117     }
118 
119     protected ExecutionResults execute(final HConnectionImpl conn) throws HBqlException {
120 
121         this.validate(conn);
122 
123         this.validateTypes();
124 
125         final WithArgs withArgs = this.getWithArgs();
126         final Set<ColumnAttrib> allWhereAttribs = withArgs.getColumnsUsedInAllWhereExprs();
127 
128         HTableWrapper tableWrapper = null;
129 
130         try {
131             tableWrapper = conn.newHTableWrapper(withArgs, this.getMappingContext().getMapping().getTableName());
132 
133             final List<RowRequest> rowRequests = withArgs.getRowRequestList(conn,
134                                                                             this.getMappingContext().getMapping(),
135                                                                             allWhereAttribs);
136 
137             int cnt = 0;
138 
139             for (final RowRequest rowRequest : rowRequests)
140                 cnt += this.delete(tableWrapper, withArgs, rowRequest);
141 
142             try {
143                 tableWrapper.getHTable().flushCommits();
144                 tableWrapper.getHTable().close();
145             }
146             catch (IOException e) {
147                 throw new HBqlException(e);
148             }
149 
150             final ExecutionResults results = new ExecutionResults("Delete count: " + cnt);
151             results.setCount(cnt);
152             return results;
153         }
154         finally {
155             // release to table pool
156             if (tableWrapper != null)
157                 tableWrapper.releaseHTable();
158         }
159     }
160 
161     private int delete(final HTableWrapper tableWrapper,
162                        final WithArgs withArgs,
163                        final RowRequest rowRequest) throws HBqlException {
164 
165         final HTableInterface table = tableWrapper.getHTable();
166         final ExpressionTree clientExpressionTree = withArgs.getClientExpressionTree();
167         final ResultScanner resultScanner = rowRequest.getResultScanner(this.getMappingContext().getMapping(),
168                                                                         withArgs,
169                                                                         table);
170 
171         int cnt = 0;
172 
173         try {
174             for (final Result result : resultScanner) {
175                 try {
176                     if (clientExpressionTree == null || clientExpressionTree.evaluate(this.getConnection(), result)) {
177 
178                         final Delete rowDelete = new Delete(result.getRow());
179 
180                         for (final String deleteItem : this.getDeleteItemList()) {
181                             if (deleteItem.endsWith(":*")) {
182                                 final String familyName = deleteItem.substring(0, deleteItem.length() - 2);
183                                 rowDelete.deleteFamily(familyName.getBytes());
184                             }
185                             else {
186                                 final int delim = deleteItem.indexOf(":");
187                                 String family = deleteItem.substring(0, delim);
188                                 String qualifier = deleteItem.substring(delim + 1, deleteItem.length());
189                                 rowDelete.deleteColumns(family.getBytes(), qualifier.getBytes());
190                             }
191                         }
192 
193                         table.delete(rowDelete);
194                         cnt++;
195                     }
196                 }
197                 catch (ResultMissingColumnException e) {
198                     // Just skip and go to next record
199                 }
200                 catch (NullColumnValueException e) {
201                     // Just skip and go to next record
202                 }
203             }
204             if (cnt > 0)
205                 table.flushCommits();
206             return cnt;
207         }
208         catch (IOException e) {
209             throw new HBqlException(e);
210         }
211     }
212 
213     public void resetParameters() {
214         this.getWithArgs().reset();
215     }
216 
217     private void collectParameters() {
218         this.getNamedParameters().addParameters(this.getWithArgs().getParameterList());
219     }
220 
221     public int setStatementParameter(final String name, final Object val) throws HBqlException {
222         final int cnt = this.getWithArgs().setParameter(name, val);
223         if (cnt == 0)
224             throw new HBqlException("Parameter name " + name + " does not exist in " + this.asString());
225         return cnt;
226     }
227 
228     public String asString() {
229 
230         final StringBuilder sbuf = new StringBuilder();
231 
232         sbuf.append("DELETE ");
233 
234         boolean firsttime = true;
235         for (final String familyName : this.originaltemList) {
236             if (!firsttime)
237                 sbuf.append(", ");
238             sbuf.append(familyName);
239             firsttime = false;
240         }
241 
242         sbuf.append(" FROM ");
243         sbuf.append(this.getMappingContext().getMappingName());
244         sbuf.append(" ");
245         sbuf.append(this.getWithArgs().asString());
246         return sbuf.toString();
247     }
248 
249     public static String usage() {
250         return "DELETE delete_item_list FROM [MAPPING] mapping_name with_clause [IF bool_expr]";
251     }
252 }