001: /*
002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: * $Id: Insert.java 3648 2007-01-29 12:16:16Z gbevin $
007: */
008: package com.uwyn.rife.database.queries;
009:
010: import com.uwyn.rife.database.Datasource;
011: import com.uwyn.rife.database.capabilities.Capabilities;
012: import com.uwyn.rife.database.exceptions.DbQueryException;
013: import com.uwyn.rife.database.exceptions.FieldsRequiredException;
014: import com.uwyn.rife.database.exceptions.TableNameRequiredException;
015: import com.uwyn.rife.database.exceptions.UnsupportedSqlFeatureException;
016: import com.uwyn.rife.database.types.SqlNull;
017: import com.uwyn.rife.site.Constrained;
018: import com.uwyn.rife.site.ConstrainedUtils;
019: import com.uwyn.rife.template.Template;
020: import com.uwyn.rife.template.TemplateFactory;
021: import com.uwyn.rife.tools.StringUtils;
022: import java.util.ArrayList;
023: import java.util.LinkedHashMap;
024: import java.util.List;
025: import java.util.Map;
026: import java.util.Set;
027:
028: /**
029: * Object representation of a SQL "INSERT" query.
030: *
031: * <p>This object may be used to dynamically construct a SQL statement in a
032: * database-independent fashion. After it is finished, it may be executed using
033: * {@link com.uwyn.rife.database.DbQueryManager#executeUpdate(Query)
034: * DbQueryManager.executeUpdate()}.
035: *
036: * @author Geert Bevin (gbevin[remove] at uwyn dot com)
037: * @author Steven Grimm (koreth[remove] at midwinter dot com)
038: * @version $Revision: 3648 $
039: * @since 1.0
040: */
041: public class Insert extends AbstractParametrizedQuery implements
042: Cloneable {
043: private String mHint = null;
044: private String mInto = null;
045: private Map<String, List<Object>> mFields = null;
046:
047: public Insert(Datasource datasource) {
048: super (datasource);
049:
050: if (null == datasource)
051: throw new IllegalArgumentException(
052: "datasource can't be null.");
053:
054: clear();
055: }
056:
057: public void clear() {
058: super .clear();
059:
060: mHint = null;
061: mInto = null;
062: mFields = new LinkedHashMap<String, List<Object>>();
063:
064: assert 0 == mFields.size();
065: }
066:
067: public String getHint() {
068: return mHint;
069: }
070:
071: public String getInto() {
072: return mInto;
073: }
074:
075: public Map<String, List<Object>> getFields() {
076: return mFields;
077: }
078:
079: public Capabilities getCapabilities() {
080: return null;
081: }
082:
083: public String getSql() throws DbQueryException {
084: if (null == mSql) {
085: if (null == mInto) {
086: throw new TableNameRequiredException("Insert");
087: } else if (0 == mFields.size()) {
088: throw new FieldsRequiredException("Insert");
089: } else {
090: Template template = TemplateFactory.SQL.get("sql."
091: + StringUtils.encodeClassname(mDatasource
092: .getAliasedDriver()) + ".insert");
093:
094: if (mHint != null) {
095: if (!template.hasValueId("HINT")) {
096: throw new UnsupportedSqlFeatureException(
097: "HINT", mDatasource.getAliasedDriver());
098: }
099: template.setValue("EXPRESSION", mHint);
100: template.setBlock("HINT", "HINT");
101: }
102:
103: template.setValue("INTO", mInto);
104:
105: // obtain the maximum number of values that are present by counting those of each field
106: int maximum_number_of_value_rows = 0;
107: for (List<Object> values : mFields.values()) {
108: if (values.size() > maximum_number_of_value_rows) {
109: maximum_number_of_value_rows = values.size();
110: }
111: }
112:
113: // create the different rows that will be inserted into the database
114: ArrayList<String> value_rows = new ArrayList<String>();
115: ArrayList<String> value_row = null;
116: Object[] column_names = mFields.keySet().toArray();
117: String column_name = null;
118: for (int current_value_row = 0; current_value_row < maximum_number_of_value_rows; current_value_row++) {
119: value_row = new ArrayList<String>();
120: for (int i = 0; i < column_names.length; i++) {
121: column_name = (String) column_names[i];
122: if (current_value_row <= mFields.get(
123: column_name).size() - 1) {
124: value_row.add(mFields.get(column_name).get(
125: current_value_row).toString());
126: } else {
127: value_row.add("NULL");
128: }
129: }
130: template.setValue("VALUES", StringUtils.join(
131: value_row, template.getBlock("SEPERATOR")));
132: value_rows.add(template.getBlock("VALUE_ROW"));
133: }
134:
135: // create the strings of the columns that values will be inserted into and which values they are
136: template.setValue("COLUMNS", StringUtils.join(
137: column_names, template.getBlock("SEPERATOR")));
138: if (1 == value_rows.size()) {
139: template.setValue("DATA", value_rows.get(0));
140: } else {
141: if (template.hasValueId("VALUE_ROWS")) {
142: template.setValue("VALUE_ROWS", StringUtils
143: .join(value_rows, template
144: .getBlock("SEPERATOR")));
145: }
146:
147: String block = template.getBlock("VALUE_ROWS");
148: if (0 == block.length()) {
149: throw new UnsupportedSqlFeatureException(
150: "MULTIPLE INSERT ROWS", mDatasource
151: .getAliasedDriver());
152: }
153: template.setValue("DATA", block);
154: }
155:
156: mSql = template.getBlock("QUERY");
157:
158: assert mSql != null;
159: assert mSql.length() > 0;
160: }
161: }
162:
163: return mSql;
164: }
165:
166: public Insert hint(String hint) {
167: clearGenerated();
168: mHint = hint;
169:
170: return this ;
171: }
172:
173: public Insert into(String into) {
174: if (null == into)
175: throw new IllegalArgumentException("into can't be null.");
176: if (0 == into.length())
177: throw new IllegalArgumentException("into can't be empty.");
178:
179: clearGenerated();
180: mInto = into;
181:
182: return this ;
183: }
184:
185: public Insert fieldSubselect(Select query) {
186: _fieldSubselect(query);
187:
188: return this ;
189: }
190:
191: protected Insert _field(String field, Object value) {
192: assert field != null;
193: assert field.length() > 0;
194:
195: clearGenerated();
196: if (!mFields.containsKey(field)) {
197: mFields.put(field, new ArrayList<Object>());
198: }
199: if (null == value) {
200: mFields.get(field).add(SqlNull.NULL);
201: } else {
202: mFields.get(field).add(value);
203: }
204:
205: return this ;
206: }
207:
208: public Insert fieldParameter(String field) {
209: return fieldParameter(field, field);
210: }
211:
212: public Insert fieldParameter(String field, String alias) {
213: if (null == field)
214: throw new IllegalArgumentException("field can't be null.");
215: if (0 == field.length())
216: throw new IllegalArgumentException("field can't be empty.");
217: if (null == alias)
218: throw new IllegalArgumentException("alias can't be null.");
219: if (0 == alias.length())
220: throw new IllegalArgumentException("alias can't be empty.");
221:
222: clearGenerated();
223:
224: addFieldParameter(alias);
225:
226: return _field(field, "?");
227: }
228:
229: public Insert field(String field, char value) {
230: return field(field, new Character(value));
231: }
232:
233: public Insert field(String field, boolean value) {
234: return field(field, Boolean.valueOf(value));
235: }
236:
237: public Insert field(String field, byte value) {
238: return field(field, new Byte(value));
239: }
240:
241: public Insert field(String field, double value) {
242: return field(field, new Double(value));
243: }
244:
245: public Insert field(String field, float value) {
246: return field(field, new Float(value));
247: }
248:
249: public Insert field(String field, int value) {
250: return field(field, new Integer(value));
251: }
252:
253: public Insert field(String field, long value) {
254: return field(field, new Long(value));
255: }
256:
257: public Insert field(String field, short value) {
258: return field(field, new Short(value));
259: }
260:
261: public Insert field(String field, Select query) {
262: if (null == query)
263: throw new IllegalArgumentException("query can't be null.");
264:
265: StringBuilder buffer = new StringBuilder();
266: buffer.append("(");
267: buffer.append(query.toString());
268: buffer.append(")");
269:
270: fieldCustom(field, buffer.toString());
271: _fieldSubselect(query);
272:
273: return this ;
274: }
275:
276: public Insert field(String field, Object value) {
277: if (null == field)
278: throw new IllegalArgumentException("field can't be null.");
279: if (0 == field.length())
280: throw new IllegalArgumentException("field can't be empty.");
281:
282: if (null == value) {
283: return _field(field, null);
284: } else {
285: return _field(field, mDatasource.getSqlConversion()
286: .getSqlValue(value));
287: }
288: }
289:
290: public Insert fieldCustom(String field, String expression) {
291: if (null == field)
292: throw new IllegalArgumentException("field can't be null.");
293: if (0 == field.length())
294: throw new IllegalArgumentException("field can't be empty.");
295:
296: if (null == expression) {
297: return _field(field, null);
298: } else {
299: return _field(field, expression);
300: }
301: }
302:
303: public Insert fields(Object[] keyValues) {
304: if (null == keyValues)
305: throw new IllegalArgumentException(
306: "keyValues can't be null.");
307: if (0 == keyValues.length)
308: throw new IllegalArgumentException(
309: "keyValues can't be empty.");
310:
311: for (int i = 0; i < keyValues.length; i += 2) {
312: if (null != keyValues[i]) {
313: field(keyValues[i].toString(), keyValues[i + 1]);
314: }
315: }
316:
317: return this ;
318: }
319:
320: public Insert fields(Object bean) throws DbQueryException {
321: return fieldsFiltered(bean, null, null);
322: }
323:
324: public Insert fieldsIncluded(Object bean, String[] includedFields)
325: throws DbQueryException {
326: return fieldsFiltered(bean, includedFields, null);
327: }
328:
329: public Insert fieldsExcluded(Object bean, String[] excludedFields)
330: throws DbQueryException {
331: return fieldsFiltered(bean, null, excludedFields);
332: }
333:
334: public Insert fieldsFiltered(Object bean, String[] includedFields,
335: String[] excludedFields) throws DbQueryException {
336: if (null == bean)
337: throw new IllegalArgumentException("bean can't be null.");
338:
339: Constrained constrained = ConstrainedUtils
340: .makeConstrainedInstance(bean);
341: Map<String, String> property_values = QueryHelper
342: .getBeanPropertyValues(bean, includedFields,
343: excludedFields, getDatasource());
344: for (String property_name : property_values.keySet()) {
345: if (!ConstrainedUtils.saveConstrainedProperty(constrained,
346: property_name, null)) {
347: continue;
348: }
349:
350: _field(property_name, property_values.get(property_name));
351: }
352:
353: return this ;
354: }
355:
356: public Insert fieldsParameters(Class beanClass)
357: throws DbQueryException {
358: return fieldsParametersExcluded(beanClass, null);
359: }
360:
361: public Insert fieldsParametersExcluded(Class beanClass,
362: String[] excludedFields) throws DbQueryException {
363: if (null == beanClass)
364: throw new IllegalArgumentException(
365: "beanClass can't be null.");
366:
367: clearGenerated();
368:
369: Constrained constrained = ConstrainedUtils
370: .getConstrainedInstance(beanClass);
371: Set<String> property_names = QueryHelper.getBeanPropertyNames(
372: beanClass, excludedFields);
373: for (String property_name : property_names) {
374: if (!ConstrainedUtils.saveConstrainedProperty(constrained,
375: property_name, null)) {
376: continue;
377: }
378:
379: addFieldParameter(property_name);
380: _field(property_name, "?");
381: }
382:
383: return this ;
384: }
385:
386: public Insert clone() {
387: Insert new_instance = (Insert) super .clone();
388: if (new_instance != null) {
389: if (mFields != null) {
390: new_instance.mFields = new LinkedHashMap<String, List<Object>>();
391:
392: List<Object> values = null;
393:
394: for (String field : mFields.keySet()) {
395: values = mFields.get(field);
396: if (values != null) {
397: values = new ArrayList<Object>(values);
398: }
399: new_instance.mFields.put(field, values);
400: }
401: }
402: }
403:
404: return new_instance;
405: }
406: }
|