001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.ConcatenationOperatorNode
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.compile;
023:
024: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
025:
026: import org.apache.derby.iapi.services.sanity.SanityManager;
027:
028: import org.apache.derby.iapi.error.StandardException;
029:
030: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
031: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
032: import org.apache.derby.iapi.types.TypeId;
033:
034: import org.apache.derby.iapi.types.ConcatableDataValue;
035: import org.apache.derby.iapi.types.BitDataValue;
036:
037: import org.apache.derby.iapi.sql.compile.TypeCompiler;
038: import org.apache.derby.iapi.types.DataTypeDescriptor;
039:
040: import org.apache.derby.iapi.services.compiler.MethodBuilder;
041: import org.apache.derby.iapi.services.compiler.LocalField;
042: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
043:
044: import org.apache.derby.iapi.reference.Limits;
045: import org.apache.derby.iapi.reference.SQLState;
046: import org.apache.derby.iapi.reference.ClassName;
047:
048: import java.sql.Types;
049:
050: import java.util.Vector;
051:
052: /**
053: * This node represents a concatenation comparison operator
054: *
055: * @author Jerry Brenner -- modified by jamie for bit and bit
056: * varying.
057: */
058:
059: public class ConcatenationOperatorNode extends BinaryOperatorNode {
060: /**
061: * Initializer for a ConcatenationOperatorNode
062: *
063: * @param leftOperand The left operand of the concatenation
064: * @param rightOperand The right operand of the concatenation
065: */
066: public void init(Object leftOperand, Object rightOperand) {
067: super .init(leftOperand, rightOperand, "||", "concatenate",
068: ClassName.ConcatableDataValue,
069: ClassName.ConcatableDataValue);
070: }
071:
072: /**
073: * overrides BindOperatorNode.bindExpression because concatenation has special
074: * requirements for parameter binding.
075: *
076: * @exception StandardException thrown on failure
077: */
078: public ValueNode bindExpression(FromList fromList,
079: SubqueryList subqueryList, Vector aggregateVector)
080: throws StandardException {
081: // deal with binding operands
082: leftOperand = leftOperand.bindExpression(fromList,
083: subqueryList, aggregateVector);
084: rightOperand = rightOperand.bindExpression(fromList,
085: subqueryList, aggregateVector);
086:
087: // deal with operand parameters
088: /*
089: Is there a ? parameter on the left?
090: If so, it's type is the type of the other parameter, with
091: maximum length for that type.
092: */
093:
094: if (leftOperand.requiresTypeFromContext()) {
095: if (rightOperand.requiresTypeFromContext()) {
096: throw StandardException.newException(
097: SQLState.LANG_BINARY_OPERANDS_BOTH_PARMS,
098: operator);
099: }
100:
101: TypeId leftType;
102:
103: /*
104: ** A ? on the left gets its type from the right. There are eight
105: ** legal types for the concatenation operator: CHAR, VARCHAR,
106: ** LONG VARCHAR, CLOB, BIT, BIT VARYING, LONG BIT VARYING, and BLOB.
107: ** If the right type is BLOB, set the parameter type to BLOB with max length.
108: ** If the right type is one of the other bit types, set the parameter type to
109: ** BIT VARYING with maximum length.
110: **
111: ** If the right type is CLOB, set parameter type to CLOB with max length.
112: ** If the right type is anything else, set it to VARCHAR with
113: ** maximum length. We count on the resolveConcatOperation method to
114: ** catch an illegal type.
115: **
116: ** NOTE: When I added the long types, I could have changed the
117: ** resulting parameter types to LONG VARCHAR and LONG BIT VARYING,
118: ** but they were already VARCHAR and BIT VARYING, and it wasn't
119: ** clear to me what effect it would have to change it. - Jeff
120: */
121: if (rightOperand.getTypeId().isBitTypeId()) {
122: if (rightOperand.getTypeId().isBlobTypeId())
123: leftType = TypeId.getBuiltInTypeId(Types.BLOB);
124: else
125: leftType = TypeId.getBuiltInTypeId(Types.VARBINARY);
126: } else {
127: if (rightOperand.getTypeId().isClobTypeId())
128: leftType = TypeId.getBuiltInTypeId(Types.CLOB);
129: else
130: leftType = TypeId.getBuiltInTypeId(Types.VARCHAR);
131: }
132:
133: leftOperand.setType(new DataTypeDescriptor(leftType, true));
134: }
135:
136: /*
137: Is there a ? parameter on the right?
138: */
139: if (rightOperand.requiresTypeFromContext()) {
140: TypeId rightType;
141:
142: /*
143: ** A ? on the right gets its type from the left. There are eight
144: ** legal types for the concatenation operator: CHAR, VARCHAR,
145: ** LONG VARCHAR, CLOB, BIT, BIT VARYING, LONG BIT VARYING, and BLOB.
146: ** If the left type is BLOB, set the parameter type to BLOB with max length.
147: ** If the left type is one of the other bit types, set the parameter type to
148: ** BIT VARYING with maximum length.
149: **
150: ** If the left type is CLOB, set parameter type to CLOB with max length.
151: ** If the left type is anything else, set it to VARCHAR with
152: ** maximum length. We count on the resolveConcatOperation method to
153: ** catch an illegal type.
154: **
155: ** NOTE: When I added the long types, I could have changed the
156: ** resulting parameter types to LONG VARCHAR and LONG BIT VARYING,
157: ** but they were already VARCHAR and BIT VARYING, and it wasn't
158: ** clear to me what effect it would have to change it. - Jeff
159: */
160: if (leftOperand.getTypeId().isBitTypeId()) {
161: if (leftOperand.getTypeId().isBlobTypeId())
162: rightType = TypeId.getBuiltInTypeId(Types.BLOB);
163: else
164: rightType = TypeId
165: .getBuiltInTypeId(Types.VARBINARY);
166: } else {
167: if (leftOperand.getTypeId().isClobTypeId())
168: rightType = TypeId.getBuiltInTypeId(Types.CLOB);
169: else
170: rightType = TypeId.getBuiltInTypeId(Types.VARCHAR);
171: }
172:
173: rightOperand
174: .setType(new DataTypeDescriptor(rightType, true));
175: }
176:
177: /* If the left operand is not a built-in type, then generate a bound conversion
178: * tree to a built-in type.
179: */
180: if (leftOperand.getTypeId().userType()) {
181: leftOperand = leftOperand.genSQLJavaSQLTree();
182: }
183:
184: /* If the right operand is not a built-in type, then generate a bound conversion
185: * tree to a built-in type.
186: */
187: if (rightOperand.getTypeId().userType()) {
188: rightOperand = rightOperand.genSQLJavaSQLTree();
189: }
190:
191: /* If either the left or right operands are non-string, non-bit types,
192: * then we generate an implicit cast to VARCHAR.
193: */
194: TypeCompiler tc = leftOperand.getTypeCompiler();
195: if (!(leftOperand.getTypeId().isStringTypeId() || leftOperand
196: .getTypeId().isBitTypeId())) {
197: leftOperand = (ValueNode) getNodeFactory().getNode(
198: C_NodeTypes.CAST_NODE,
199: leftOperand,
200: DataTypeDescriptor.getBuiltInDataTypeDescriptor(
201: Types.VARCHAR, true, tc
202: .getCastToCharWidth(leftOperand
203: .getTypeServices())),
204: getContextManager());
205: ((CastNode) leftOperand).bindCastNodeOnly();
206: }
207: tc = rightOperand.getTypeCompiler();
208: if (!(rightOperand.getTypeId().isStringTypeId() || rightOperand
209: .getTypeId().isBitTypeId())) {
210: rightOperand = (ValueNode) getNodeFactory().getNode(
211: C_NodeTypes.CAST_NODE,
212: rightOperand,
213: DataTypeDescriptor.getBuiltInDataTypeDescriptor(
214: Types.VARCHAR, true, tc
215: .getCastToCharWidth(rightOperand
216: .getTypeServices())),
217: getContextManager());
218: ((CastNode) rightOperand).bindCastNodeOnly();
219: }
220:
221: /*
222: ** Set the result type of this operator based on the operands.
223: ** By convention, the left operand gets to decide the result type
224: ** of a binary operator.
225: */
226: tc = leftOperand.getTypeCompiler();
227: setType(resolveConcatOperation(leftOperand.getTypeServices(),
228: rightOperand.getTypeServices()));
229:
230: /*
231: ** Make sure the maximum width set for the result doesn't exceed the result type's maximum width
232: */
233: if (SanityManager.DEBUG) {
234: if (getTypeServices().getMaximumWidth() > getTypeId()
235: .getMaximumMaximumWidth()) {
236: SanityManager
237: .THROWASSERT("The maximum length "
238: + getTypeServices().getMaximumWidth()
239: + " for the result type "
240: + getTypeId().getSQLTypeName()
241: + " can't be greater than it's maximum width of result's typeid"
242: + getTypeId().getMaximumMaximumWidth());
243: }
244: }
245:
246: /*
247: ** Now that we know the target interface type, set it. This assumes
248: ** that both operands have the same interface type, which is a safe
249: ** assumption for the concatenation operator.
250: */
251: this .setLeftRightInterfaceType(tc.interfaceName());
252:
253: return this ;
254: }
255:
256: /**
257: * Resolve a concatenation operator
258: *
259: * @param leftType The DataTypeDescriptor of the left operand
260: * @param rightType The DataTypeDescriptor of the right operand
261: *
262: * @return A DataTypeDescriptor telling the result type of the
263: * concatenate operation
264: *
265: * @exception StandardException BinaryOperatorNotSupported
266: * Thrown when a BinaryOperator is not supported
267: * on the operand types.
268: */
269: private DataTypeDescriptor resolveConcatOperation(
270: DataTypeDescriptor leftType, DataTypeDescriptor rightType)
271: throws StandardException {
272: TypeId leftTypeId;
273: TypeId rightTypeId;
274: String higherType;
275: int resultLength;
276: boolean nullable;
277:
278: leftTypeId = leftType.getTypeId();
279: rightTypeId = rightType.getTypeId();
280:
281: /*
282: ** Check the right type to be sure it's a concatable. By convention,
283: ** we call this method off the TypeId of the left operand, so if
284: ** we get here, we know the left operand is a concatable.
285: */
286: /*
287: ** Make sure we haven't been given a char and a
288: ** bit to concatenate.
289: */
290:
291: if (!leftTypeId.isConcatableTypeId()
292: || !rightTypeId.isConcatableTypeId()
293: || (rightTypeId.isBitTypeId() && leftTypeId
294: .isStringTypeId())
295: || (leftTypeId.isBitTypeId() && rightTypeId
296: .isStringTypeId()))
297: throw StandardException.newException(
298: SQLState.LANG_DB2_FUNCTION_INCOMPATIBLE, "||",
299: "FUNCTION");
300:
301: /*
302: ** The types aren't the same. The result of the operation is the
303: ** type of higher precedence.
304: */
305:
306: higherType = (leftTypeId.typePrecedence() >= rightTypeId
307: .typePrecedence()) ? leftType.getTypeName() : rightType
308: .getTypeName();
309:
310: /* Get the length of the result */
311: resultLength = leftType.getMaximumWidth()
312: + rightType.getMaximumWidth();
313:
314: /*
315: ** Use following chart to handle overflow
316: ** operands CHAR(A) CHAR(B) and A+B<255 then result is CHAR(A+B)
317: ** operands CHAR FOR BIT DATA(A) CHAR FOR BIT DATA(B) and A+B<255 then result is CHAR FOR BIT DATA(A+B)
318: **
319: ** operands CHAR(A) CHAR(B) and A+B>254 then result is VARCHAR(A+B)
320: ** operands CHAR FOR BIT DATA(A) CHAR FOR BIT DATA(B) and A+B>254 then result is VARCHAR FOR BIT DATA(A+B)
321: **
322: ** operands CHAR(A) VARCHAR(B) and A+B<4001 then result is VARCHAR(A+B)
323: ** operands CHAR FOR BIT DATA(A) VARCHAR FOR BIT DATA(B) and A+B<4001 then result is VARCHAR FOR BIT DATA(A+B)
324: **
325: ** operands CHAR(A) VARCHAR(B) and A+B>4000 then result is LONG VARCHAR
326: ** operands CHAR FOR BIT DATA(A) VARCHAR FOR BIT DATA(B) and A+B>4000 then result is LONG VARCHAR FOR BIT DATA
327: **
328: ** operands CHAR(A) LONG VARCHAR then result is LONG VARCHAR
329: ** operands CHAR FOR BIT DATA(A) LONG VARCHAR FOR BIT DATA then result is LONG VARCHAR FOR BIT DATA
330: **
331: ** operands VARCHAR(A) VARCHAR(B) and A+B<4001 then result is VARCHAR(A+B)
332: ** operands VARCHAR FOR BIT DATA(A) VARCHAR FOR BIT DATA(B) and A+B<4001 then result is VARCHAR FOR BIT DATA(A+B)
333: **
334: ** operands VARCHAR(A) VARCHAR(B) and A+B>4000 then result is LONG VARCHAR
335: ** operands VARCHAR FOR BIT DATA(A) VARCHAR FOR BIT DATA(B) and A+B>4000 then result is LONG VARCHAR FOR BIT DATA
336: **
337: ** operands VARCHAR(A) LONG VARCHAR then result is LONG VARCHAR
338: ** operands VARCHAR FOR BIT DATA(A) LONG VARCHAR FOR BIT DATA then result is LONG VARCHAR FOR BIT DATA
339: **
340: ** operands LONG VARCHAR, LONG VARCHAR then result is LONG VARCHAR
341: ** operands LONG VARCHAR FOR BIT DATA, LONG VARCHAR FOR BIT DATA then result is LONG VARCHAR FOR BIT DATA
342: **
343: ** operands CLOB(A), CHAR(B) then result is CLOB(MIN(A+B,2G))
344: ** operands CLOB(A), VARCHAR(B) then result is CLOB(MIN(A+B,2G))
345: ** operands CLOB(A), LONG VARCHAR then result is CLOB(MIN(A+32K,2G))
346: ** operands CLOB(A), CLOB(B) then result is CLOB(MIN(A+B,2G))
347: **
348: ** operands BLOB(A), CHAR FOR BIT DATA(B) then result is BLOB(MIN(A+B,2G))
349: ** operands BLOB(A), VARCHAR FOR BIT DATA(B) then result is BLOB(MIN(A+B,2G))
350: ** operands BLOB(A), LONG VARCHAR FOR BIT DATA then result is BLOB(MIN(A+32K,2G))
351: ** operands BLOB(A), BLOB(B) then result is BLOB(MIN(A+B,2G))
352: **
353: ** operands CHAR(A)/VARCHAR(A)/LONGVARCHAR, LONGVARCHAR and "concatenated string length">32700 does not cause automatic escalation
354: ** to LOB for compatibility with previous releases. Any such cases would result in an error at runtime
355: **
356: */
357: //in the following code, I can assume that left and right operands both will be either char kind
358: //of datatypes or they will be both binary kind of datatypes. That's because operand datatypes
359: //mismatch has already been handled earlier
360: if (leftTypeId.getJDBCTypeId() == Types.CHAR
361: || leftTypeId.getJDBCTypeId() == Types.BINARY) {
362: switch (rightTypeId.getJDBCTypeId()) {
363: case Types.CHAR:
364: case Types.BINARY:
365: if (resultLength > Limits.DB2_CHAR_MAXWIDTH) {
366: if (rightTypeId.getJDBCTypeId() == Types.CHAR)
367: //operands CHAR(A) CHAR(B) and A+B>254 then result is VARCHAR(A+B)
368: higherType = TypeId.VARCHAR_NAME;
369: else
370: //operands CHAR FOR BIT DATA(A) CHAR FOR BIT DATA(B) and A+B>254 then result is VARCHAR FOR BIT DATA(A+B)
371: higherType = TypeId.VARBIT_NAME;
372: }
373: break;
374:
375: case Types.VARCHAR:
376: case Types.VARBINARY:
377: if (resultLength > Limits.DB2_CONCAT_VARCHAR_LENGTH) {
378: if (rightTypeId.getJDBCTypeId() == Types.VARCHAR)
379: //operands CHAR(A) VARCHAR(B) and A+B>4000 then result is LONG VARCHAR
380: higherType = TypeId.LONGVARCHAR_NAME;
381: else
382: //operands CHAR FOR BIT DATA(A) VARCHAR FOR BIT DATA(B) and A+B>4000 then result is LONG VARCHAR FOR BIT DATA
383: higherType = TypeId.LONGVARBIT_NAME;
384: }
385: break;
386:
387: case Types.CLOB:
388: case Types.BLOB:
389: //operands CHAR(A), CLOB(B) then result is CLOB(MIN(A+B,2G))
390: //operands CHAR FOR BIT DATA(A), BLOB(B) then result is BLOB(MIN(A+B,2G))
391: resultLength = clobBlobHandling(rightType, leftType);
392: break;
393: }
394: } else if (leftTypeId.getJDBCTypeId() == Types.VARCHAR) {
395: switch (rightTypeId.getJDBCTypeId()) {
396: case Types.CHAR: //operands CHAR(A) VARCHAR(B) and A+B>4000 then result is LONG VARCHAR
397: case Types.VARCHAR: //operands VARCHAR(A) VARCHAR(B) and A+B>4000 then result is LONG VARCHAR
398: if (resultLength > Limits.DB2_CONCAT_VARCHAR_LENGTH)
399: higherType = TypeId.LONGVARCHAR_NAME;
400: break;
401:
402: case Types.CLOB:
403: //operands VARCHAR(A), CLOB(B) then result is CLOB(MIN(A+B,2G))
404: resultLength = clobBlobHandling(rightType, leftType);
405: break;
406: }
407: } else if (leftTypeId.getJDBCTypeId() == Types.VARBINARY) {
408: switch (rightTypeId.getJDBCTypeId()) {
409: case Types.BINARY: //operands CHAR FOR BIT DATA(A) VARCHAR FOR BIT DATA(B) and A+B>4000 then result is LONG VARCHAR FOR BIT DATA
410: case Types.VARBINARY://operands VARCHAR FOR BIT DATA(A) VARCHAR FOR BIT DATA(B) and A+B>4000 then result is LONG VARCHAR FOR BIT DATA
411: if (resultLength > Limits.DB2_CONCAT_VARCHAR_LENGTH)
412: higherType = TypeId.LONGVARBIT_NAME;
413: break;
414:
415: case Types.BLOB:
416: //operands VARCHAR FOR BIT DATA(A), BLOB(B) then result is BLOB(MIN(A+B,2G))
417: resultLength = clobBlobHandling(rightType, leftType);
418: break;
419: }
420: } else if (leftTypeId.getJDBCTypeId() == Types.CLOB
421: || leftTypeId.getJDBCTypeId() == Types.BLOB) {
422: //operands CLOB(A), CHAR(B) then result is CLOB(MIN(A+B,2G))
423: //operands CLOB(A), VARCHAR(B) then result is CLOB(MIN(A+B,2G))
424: //operands CLOB(A), LONG VARCHAR then result is CLOB(MIN(A+32K,2G))
425: //operands CLOB(A), CLOB(B) then result is CLOB(MIN(A+B,2G))
426: //operands BLOB(A), CHAR FOR BIT DATA(B) then result is BLOB(MIN(A+B,2G))
427: //operands BLOB(A), VARCHAR FOR BIT DATA(B) then result is BLOB(MIN(A+B,2G))
428: //operands BLOB(A), LONG VARCHAR FOR BIT DATA then result is BLOB(MIN(A+32K,2G))
429: //operands BLOB(A), BLOB(B) then result is BLOB(MIN(A+B,2G))
430: resultLength = clobBlobHandling(leftType, rightType);
431: } else if (rightTypeId.getJDBCTypeId() == Types.CLOB
432: || rightTypeId.getJDBCTypeId() == Types.BLOB) {
433: //operands LONG VARCHAR, CLOB(A) then result is CLOB(MIN(A+32K,2G))
434: //operands LONG VARCHAR FOR BIT DATA, BLOB(A) then result is BLOB(MIN(A+32K,2G))
435: resultLength = clobBlobHandling(rightType, leftType);
436: }
437:
438: //bug - 5837. long varchar and long binary can't hold more data than their specific limits. If this length is violated by resulting
439: //concatenated string, an exception will be thrown at execute time.
440: if (higherType.equals(TypeId.LONGVARCHAR_NAME))
441: resultLength = TypeId.LONGVARCHAR_MAXWIDTH;
442: else if (higherType.equals(TypeId.LONGVARBIT_NAME))
443: resultLength = TypeId.LONGVARBIT_MAXWIDTH;
444:
445: /*
446: ** Result Length can't be negative
447: */
448: if (SanityManager.DEBUG) {
449: if (resultLength < 0) {
450: SanityManager
451: .THROWASSERT("There should not be an overflow of maximum length for any result type at this point. Overflow for BLOB/CLOB has already been handled earlier");
452: }
453: }
454:
455: /* The result is nullable if either side is nullable */
456: nullable = leftType.isNullable() || rightType.isNullable();
457:
458: /*
459: ** Create a new DataTypeDescriptor that has the correct
460: ** type and nullability.
461: **
462: ** It's OK to call the implementation of the DataTypeDescriptorFactory
463: ** here, because we're in the same package.
464: */
465: return new DataTypeDescriptor(TypeId
466: .getBuiltInTypeId(higherType), nullable, resultLength);
467: }
468:
469: /*
470: *for conatenation operator, we generate code as follows
471: *field = method(p1, p2, field);
472: *what we are ensuring here is if field is null then initialize it to NULL SQLxxx type.
473: *Because of the following, at execution time, SQLxxx concatenate method do not have to
474: *worry about field coming in as null
475: */
476: protected void initializeResultField(ExpressionClassBuilder acb,
477: MethodBuilder mb, LocalField resultField)
478: throws StandardException {
479: mb.conditionalIfNull();//get the field on the stack and if it is null
480: acb.generateNull(mb, getTypeCompiler());// yes, it is, hence create a NULL SQLxxx type object and put that on stack
481: mb.startElseCode(); //no, it is not null
482: mb.getField(resultField); //so put it back on the stack
483: mb.completeConditional(); //complete if else block
484: }
485:
486: private static int clobBlobHandling(
487: DataTypeDescriptor clobBlobType,
488: DataTypeDescriptor otherType) throws StandardException {
489: int resultLength;
490:
491: if (otherType.getTypeId().getJDBCTypeId() == Types.LONGVARCHAR
492: || otherType.getTypeId().getJDBCTypeId() == Types.LONGVARBINARY) {
493: //operands CLOB(A), LONG VARCHAR then result is CLOB(MIN(A+32K,2G))
494: //operands BLOB(A), LONG VARCHAR FOR BIT DATA then result is BLOB(MIN(A+32K,2G))
495: resultLength = clobBlobType.getMaximumWidth() + 32768;
496: } else {
497: //operands CLOB(A), CHAR(B) then result is CLOB(MIN(A+B,2G))
498: //operands CLOB(A), VARCHAR(B) then result is CLOB(MIN(A+B,2G))
499: //operands CLOB(A), CLOB(B) then result is CLOB(MIN(A+B,2G))
500: //operands BLOB(A), CHAR FOR BIT DATA(B) then result is BLOB(MIN(A+B,2G))
501: //operands BLOB(A), VARCHAR FOR BIT DATA(B) then result is BLOB(MIN(A+B,2G))
502: //operands BLOB(A), BLOB(B) then result is BLOB(MIN(A+B,2G))
503: resultLength = clobBlobType.getMaximumWidth()
504: + otherType.getMaximumWidth();
505: }
506:
507: if (resultLength < 1) //this mean A+B or A+32K is bigger than 2G
508: return (Integer.MAX_VALUE);
509: else
510: return (resultLength);
511:
512: }
513: }
|