alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (Statement.java)

This example Glassfish source code file (Statement.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

arraylist, constraintfield, constraintnode, constraintsubquery, jdbc, noi18n, noi18n, object, object, op_irregular_mask, op_where_mask, sql, string, string, stringbuffer, stringbuffer, util

The Glassfish Statement.java source code

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

/*
 * Statement.java
 *
 * Created on March 3, 2000
 *
 */

package com.sun.jdo.spi.persistence.support.sqlstore.sql.generator;

import org.netbeans.modules.dbschema.ColumnElement;
import org.netbeans.modules.dbschema.TableElement;
import com.sun.jdo.api.persistence.support.JDOFatalInternalException;
import com.sun.jdo.spi.persistence.support.sqlstore.ActionDesc;
import com.sun.jdo.spi.persistence.support.sqlstore.database.DBVendorType;
import com.sun.jdo.spi.persistence.support.sqlstore.model.LocalFieldDesc;
import com.sun.jdo.spi.persistence.support.sqlstore.sql.constraint.*;
import org.glassfish.persistence.common.I18NHelper;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;

/**
 * This class is used to represent a SQL statement.
 */
public abstract class Statement extends Object implements Cloneable {

    private static final Integer ONE = new Integer(1);

    protected static final int OP_PREFIX_MASK =     0x001; // 1

    protected static final int OP_INFIX_MASK =      0x002; // 2

    protected static final int OP_POSTFIX_MASK =    0x004; // 4

    protected static final int OP_PAREN_MASK =      0x008; // 8

    protected static final int OP_ORDERBY_MASK =    0x010; // 16

    protected static final int OP_WHERE_MASK =      0x020; // 32

    protected static final int OP_IRREGULAR_MASK =  0x040; // 64

    protected static final int OP_OTHER_MASK =      0x080; // 128

    protected static final int OP_PARAM_MASK =      0x100; // 256

    protected static final int OP_BINOP_MASK = 2 * OP_PARAM_MASK | OP_WHERE_MASK | OP_INFIX_MASK; // 546

    protected static final int OP_FUNC_MASK = OP_PARAM_MASK | OP_PREFIX_MASK | OP_PAREN_MASK | OP_WHERE_MASK; // 297

    protected static final int OP_PCOUNT_MASK = 3 * OP_PARAM_MASK; // 768

    protected StringBuffer statementText;

    private String quoteCharStart;

    private String quoteCharEnd;

    /** array of ColumnRef */
    protected ArrayList columns;

    Constraint constraint;

    protected InputDesc inputDesc;

    int action;

    /** array of QueryTable */
    public ArrayList tableList;

    protected DBVendorType vendorType;

    protected ArrayList secondaryTableStatements;

    /**
     * I18N message handler
     */
    protected final static ResourceBundle messages = I18NHelper.loadBundle(
           "com.sun.jdo.spi.persistence.support.sqlstore.Bundle", // NOI18N
            Statement.class.getClassLoader());


    public Statement(DBVendorType vendorType) {

        inputDesc = new InputDesc();
        columns = new ArrayList();
        constraint = new Constraint();
        tableList = new ArrayList();
        this.vendorType = vendorType;

        if (vendorType.getQuoteSpecialOnly() == false) {
            // DO NOT SUPPORT QUOTING OTHERWISE
            this.quoteCharStart = vendorType.getQuoteCharStart();
            this.quoteCharEnd = vendorType.getQuoteCharEnd();
        }
    }

    public void addQueryTable(QueryTable table) {
        //
        // First check to make sure this is not a duplicate.
        //
        if (tableList.indexOf(table) == -1) {
            tableList.add(table);
        }
    }

    protected ColumnRef getColumnRef(ColumnElement columnElement) {
        //
        // Check whether this column has already been added.
        // If so, simply return.
        //
        int size = columns.size();

        for (int i = 0; i < size; i++) {
            ColumnRef cref = (ColumnRef) columns.get(i);

            if (cref.getColumnElement() == columnElement) return cref;
        }

        return null;
    }

    protected void addColumnRef(ColumnRef columnRef) {
        columnRef.setIndex(columns.size()+1);
        columns.add(columnRef);
    }

    /**
     * Adds a comparison on local field <CODE>lf and value value.
     */
    public void addConstraint(LocalFieldDesc lf, Object value) {
        int operation;
        if (value == null) {
            operation = ActionDesc.OP_NULL;
        } else {
            constraint.addValue(value, lf);
            if (lf.isPrimitiveMappedToNullableColumn() ||
                       (vendorType.mapEmptyStringToNull() && lf.getType() == String.class)) {
                // Primitive fields mapped to nullable columns might hold
                // a default value indicting that the actual db column is null.
                // Databases might treat zero length Strings as null.
                operation = ActionDesc.OP_MAYBE_NULL;
            } else {
                // Object type fields or primitive fields
                // mapped to non nullable columns are compared exactly
                operation = ActionDesc.OP_EQ;
            }
        }
        constraint.addField(lf);
        constraint.addOperation(operation);
    }

    public DBVendorType getVendorType() {
        return vendorType;
    }

    public void appendTableText(StringBuffer text, QueryTable table) {
        appendQuotedText(text, table.getTableDesc().getName());
        text.append(" t"); // NOI18N
        text.append(table.getTableIndex());
    }

    /**
     * Append <code>text surrounded by quote char to buffer
     * @param buffer The given buffer
     * @param text The given text
     */
    protected void appendQuotedText(StringBuffer buffer, String text) {
        buffer.append(quoteCharStart);
        buffer.append(text);
        buffer.append(quoteCharEnd);
    }

    /**
     * Returns the SQL text for the query described by this object.
     *
     * @return The text of the SQL query described by this object.
     */
    public String getText() {

        if (statementText == null) {
            generateStatementText();
        }


        return statementText.toString();
    }

    /**
     * Generates the SQL text for the query described by this object.
     */
    protected abstract void generateStatementText();

    /**
     * Processes the constraint stack and adds it to the query.
     * This means turning the constraint stack into SQL text and
     * adding it to the where clause.
     *
     * @return Where clause based on the constraint stack.
     */
    public StringBuffer processConstraints() {
        StringBuffer whereText = new StringBuffer();
        List stack = constraint.getConstraints();

        while (stack.size() > 0) {
            ConstraintNode node = (ConstraintNode) stack.get(stack.size() - 1);

            if (!(node instanceof ConstraintOperation)) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "core.generic.notinstanceof", // NOI18N
                        node.getClass().getName(), "ConstraintOperation")); // NOI18N
            }

            processRootConstraint((ConstraintOperation) node, stack, whereText);
        }

        return whereText;
    }

    protected void processRootConstraint(ConstraintOperation opNode,
                                         List stack,
                                         StringBuffer whereText) {
        int op = opNode.operation;
        int opInfo = operationFormat(op);

        if ((opInfo & OP_WHERE_MASK) > 0) {
            String constraint = getWhereText(stack);
            if (whereText.length() > 0 && constraint.length() > 0) {
                // This is neccessary, if the constraint stack is "un-balanced",
                // see OrderingTest#ordering006 for an example.
                whereText.append(" and ");
            }
            whereText.append(constraint);
        } else {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "sqlstore.sql.generator.statement.unexpectedconstraint", op)); // NOI18N
        }
    }

    /**
     * Get QueryPlan for this statement
     * @return QueryPlan for this statement
     */
    public abstract QueryPlan getQueryPlan();

    /**
     * Constructs the where clause for the statement from
     * the constraint stack.
     *
     * @param stack
     * 	The stack parameter holds the constraint stack to be decoded.
     *
     *  RESOLVE:  We don't support constraints on multiple statements yet.
     *  We would need to sort constraints out by statement and do something
     *  about constraints that span statements (e.g. t1.c1 = t2.c2).
     */
    protected String getWhereText(List stack) {

        StringBuffer result = new StringBuffer();
        ConstraintNode node;

        if (stack.size() == 0) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.stackempty")); // NOI18N
        }

        node = (ConstraintNode) stack.get(stack.size() - 1);
        stack.remove(stack.size() - 1);

        if (node instanceof ConstraintParamIndex) {
            processConstraintParamIndex((ConstraintParamIndex) node, result);
        } else if (node instanceof ConstraintValue) {
            processConstraintValue((ConstraintValue) node, result);
        } else if (node instanceof ConstraintField) {
            processConstraintField((ConstraintField) node, result);
        } else if (node instanceof ConstraintConstant) {
            result.append(((ConstraintConstant) node).value.toString());
        } else if (node instanceof ConstraintOperation) {
            processConstraintOperation((ConstraintOperation) node, stack, result);
        } else {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.illegalnode", // NOI18N
                    node.getClass().getName()));
        }

        return result.toString();
    }

    protected void processConstraintParamIndex(ConstraintParamIndex node, StringBuffer result) {
        // DB2 requires cast for parameter markers involved in numeric expressions.
        result.append(vendorType.getParameterMarker(node.getType()));
        Integer index = node.getIndex();
        inputDesc.values.add(new InputParamValue(index, getColumnElementForValueNode(node) ));
    }

    protected void processConstraintValue(ConstraintValue node, StringBuffer result) {
        boolean generateValueInSQLStatement = false;
        String strToAppend = "?"; // NOI18N

        // DB2 requires cast for parameter markers involved in numeric expressions.
        // For DB2, do not generate parameter markers, but inline values in generated SQL.
        // TODO: Inline numerics for all the databases not just DB2.

        if (vendorType.isInlineNumeric()) {
        // TODO: Ask Michael to pass on type for values also as enums.
        // Suggestion : Convert FieldTypeEnumeration to a class. Implement methods like
        // isNumeric(int type) for following if condition
            Object value = node.getValue();
            if (value != null && value instanceof Number) {
                generateValueInSQLStatement = true;
                strToAppend = value.toString();
            }
        }
        result.append(strToAppend);

        if(!generateValueInSQLStatement) {
            // We have added a "?" to sql. Add value to inputDesc
            generateInputValueForConstraintValueNode(node);
        }
    }

    protected QueryPlan getOriginalPlan(ConstraintField fieldNode) {
        return (fieldNode.originalPlan != null) ? fieldNode.originalPlan : getQueryPlan();
    }

    private void processConstraintField(ConstraintField fieldNode, StringBuffer result) {
        LocalFieldDesc desc = null;

        QueryPlan thePlan = getOriginalPlan(fieldNode);

        if (fieldNode instanceof ConstraintFieldDesc) {
            desc = ((ConstraintFieldDesc) fieldNode).desc;
        } else if (fieldNode instanceof ConstraintFieldName) {
            desc = thePlan.config.getLocalFieldDesc(((ConstraintFieldName) fieldNode).name);
        } else {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.generic.notinstanceof", // NOI18N
                    fieldNode.getClass().getName(),
                    "ConstraintFieldDesc/ConstraintFieldName")); // NOI18N
        }
        generateColumnText(desc, thePlan, result);
    }

    /**
     * Generates the column text for field <code>desc.
     * The column has to be associated to the corresponding query table
     * from the list <code>tableList.
     * For fields mapped to multiple columns choose one column to be included,
     * as all mapped columns should have the same value.
     *
     * @param desc Local field descriptor to be included in the constraint text.
     * @param thePlan Query plan corresponding to <code>desc.
     * @param sb String buffer taking the resulting text.
     */
    protected void generateColumnText(LocalFieldDesc desc, QueryPlan thePlan,
                                      StringBuffer sb) {
        QueryTable table = null;
        ColumnElement column = null;
        Iterator iter = desc.getColumnElements();

        while (iter.hasNext() && table == null) {
            column = (ColumnElement) iter.next();

            // For updates, the member variable tableList is complete
            // at this point and includes only the table being updated.
            // For selects, new tables are still added to tableList
            // when join constraints are processed. Take the table list
            // from the query plan to find the table matching the column.
            if (action == QueryPlan.ACT_SELECT) {
                table = thePlan.findQueryTable(column.getDeclaringTable());
            } else {
                table = findQueryTable(column.getDeclaringTable());
            }
        }

        if (table == null) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.configuration.fieldnotable", // NOI18N
                    desc.getName()));
        }

        // Select statements might include columns from several tables.
        // Qualify the column with the table index.
        if (action == QueryPlan.ACT_SELECT) {
            sb.append("t").append(table.getTableIndex()).append("."); // NOI18N
        }

        appendQuotedText(sb, column.getName().getName());
    }

    /**
     * Matches the table element <code>tableElement to the
     * corresponding query table from the list <code>tableList.
     *
     * @param tableElement Table element to be found.
     * @return Query table object corresponding to table element.
     * @see QueryPlan#findQueryTable(TableElement)
     */
    protected QueryTable findQueryTable(TableElement tableElement) {
        QueryTable table = null;

        for (Iterator iter = tableList.iterator(); iter.hasNext() && table == null; ) {
            QueryTable t = (QueryTable) iter.next();
            if (t.getTableDesc().getTableElement() == tableElement) {
            // if (t.getTableDesc().getTableElement().equals(tableElement)) {
                table = t;
            }
        }

        return table;
    }

    private void processConstraintOperation(ConstraintOperation opNode,
                                            List stack,
                                            StringBuffer result) {
        int opCode = opNode.operation;
        int format = operationFormat(opCode);

        if ((format & OP_IRREGULAR_MASK) == 0) {
            processFunctionOrBinaryOperation(format, opCode, stack, result);
        } else {
            processIrregularOperation(opNode, opCode, stack, result);
        }
    }

    private void processFunctionOrBinaryOperation(int format,
                                                  int opCode,
                                                  List stack,
                                                  StringBuffer result) {

        if ((format & OP_PREFIX_MASK) > 0) {
            result.append(prefixOperator(opCode));
        }

        if ((format & OP_PCOUNT_MASK) > 0) {
            if ((format & OP_PAREN_MASK) > 0) {
                result.append("("); // NOI18N
            }

            result.append(getWhereText(stack));

            for (int i = 0; i < ((format & OP_PCOUNT_MASK) / OP_PARAM_MASK) - 1; i++) {
                if ((format & OP_INFIX_MASK) > 0) {
                    // opCode for which OP_BINOP_MASK is set
                    result.append(infixOperator(opCode, i - 1));
                } else {
                    // opCode for which OP_FUNC_MASK is set
                    result.append(", "); // NOI18N
                }

                result.append(getWhereText(stack));
            }

            if ((format & OP_PAREN_MASK) > 0) {
                result.append(")"); // NOI18N
            }
        }

        if ((format & OP_POSTFIX_MASK) > 0) {
            result.append(postfixOperator(opCode));
        }
    }

    protected void processIrregularOperation(ConstraintOperation opNode,
                                             int opCode,
                                             List stack,
                                             StringBuffer result) {
        switch (opCode) {
            case ActionDesc.OP_NULL:
            case ActionDesc.OP_NOTNULL:
                processNullOperation(opCode, stack, result);
                break;
           case ActionDesc.OP_BETWEEN:
                if (stack.size() < 3) {
                    throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                            "core.constraint.stackempty")); // NOI18N
                }

                if (!(stack.get(stack.size() - 1) instanceof ConstraintField)) {
                    throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                            "core.constraint.needfieldnode")); // NOI18N
                } else {
                    result.append(getWhereText(stack));
                    result.append(" between "); // NOI18N
                }
                result.append(getWhereText(stack));
                result.append(" and ");
                result.append(getWhereText(stack));
                break;
            case ActionDesc.OP_IN:
            case ActionDesc.OP_NOTIN:
                processInOperation(opCode, stack, result);
                break;
            case ActionDesc.OP_NOTEXISTS:
            case ActionDesc.OP_EXISTS:
                if (!(opNode instanceof ConstraintSubquery)) {
                    throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                            "core.generic.notinstanceof", // NOI18N
                            opNode.getClass().getName(), "ConstraintSubquery")); // NOI18N
                }

                ConstraintSubquery sqNode = (ConstraintSubquery) opNode;

                result.append(prefixOperator(opCode));
                result.append("("); // NOI18N

                Statement sqstmt = (Statement) sqNode.plan.statements.get(0);

                result.append(sqstmt.getText());

                result.append(")"); // NOI18N
                break;
            case ActionDesc.OP_LIKE_ESCAPE:
                if (stack.size() < 3) {
                    throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                            "core.constraint.stackempty")); // NOI18N
                }

                if (vendorType.supportsLikeEscape()) {
                    if (!(stack.get(stack.size() - 1) instanceof ConstraintField)) {
                        throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                                "core.constraint.needfieldnode")); // NOI18N
                    } else {
                        result.append(getWhereText(stack));
                        result.append(" LIKE "); // NOI18N
                    }
                    result.append(getWhereText(stack));
                    result.append(vendorType.getLeftLikeEscape());
                    result.append(" ESCAPE "); // NOI18N
                    result.append(getWhereText(stack));
                    result.append(vendorType.getRightLikeEscape());
                } else {
                    throw new JDOFatalInternalException(
                            I18NHelper.getMessage(messages,
                                    "sqlstore.sql.generator.statement.likeescapenotsupported")); //NOI18N
                }

                break;
            case ActionDesc.OP_SUBSTRING:
                if (stack.size() < 3) {
                    throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                            "core.constraint.stackempty")); // NOI18N
                }

                result.append(vendorType.getSubstring());
                result.append("("); // NOI18N
                result.append(getWhereText(stack));
                result.append(vendorType.getSubstringFrom());
                result.append(getWhereText(stack));
                result.append(vendorType.getSubstringFor());
                result.append(getWhereText(stack));
                result.append(")"); // NOI18N
                break;
            case ActionDesc.OP_POSITION:
                if (stack.size() < 2) {
                    throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                            "core.constraint.stackempty")); // NOI18N
                }

                result.append(vendorType.getPosition());
                result.append("("); // NOI18N
                boolean swap = vendorType.isPositionSearchSource();
                if (swap) {
                    ConstraintNode expr =
                            (ConstraintNode)stack.remove(stack.size() - 1);
                    ConstraintNode pattern =
                            (ConstraintNode)stack.remove(stack.size() - 1);
                    stack.add(expr);
                    stack.add(pattern);
                }

                result.append(getWhereText(stack));
                result.append(vendorType.getPositionSep());
                result.append(" ").append(getWhereText(stack)); // NOI18N
                result.append(")"); // NOI18N
                break;
            case ActionDesc.OP_POSITION_START:
                if (stack.size() < 3) {
                    throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                            "core.constraint.stackempty")); // NOI18N
                }

                boolean swapArgs = vendorType.isPositionSearchSource();
                boolean threeArgs = vendorType.isPositionThreeArgs();

                if (threeArgs) {
                    if (swapArgs) {
                        ConstraintNode expr =
                                (ConstraintNode)stack.remove(stack.size() - 1);
                        ConstraintNode pattern =
                                (ConstraintNode)stack.remove(stack.size() - 1);
                        stack.add(expr);
                        stack.add(pattern);
                    }
                    result.append(vendorType.getPosition());
                    result.append("("); // NOI18N
                    result.append(getWhereText(stack));
                    result.append(vendorType.getPositionSep());
                    result.append(" ").append(getWhereText(stack)); // NOI18N
                    result.append(vendorType.getPositionSep());
                    result.append(" ").append(getWhereText(stack)); // NOI18N
                    result.append(")"); // NOI18N
                } else { //twoArgs
                    ConstraintValue valueNode =
                            (ConstraintValue)stack.remove(stack.size() - 3);
                    if (valueNode != null && ONE.equals(valueNode.getValue())) {
                        stack.add(new ConstraintOperation(ActionDesc.OP_POSITION));
                        result.append(getWhereText(stack));
                    } else {
                        throw new JDOFatalInternalException(
                                I18NHelper.getMessage(messages,
                                        "sqlstore.sql.generator.statement.positionthreeargsnotsupported")); // NOI18N
                    }
                }
                break;
            case ActionDesc.OP_MAYBE_NULL:
                processMaybeNullOperation(stack, result);
                break;
            case ActionDesc.OP_MOD:
                if (stack.size() < 2) {
                    throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                            "core.constraint.stackempty")); // NOI18N
                }
                result.append(prefixOperator(opCode));
                result.append("("); // NOI18N
                result.append(getWhereText(stack));
                result.append(", "); // NOI18N
                result.append(getWhereText(stack));
                result.append(")"); // NOI18N
                break;
            case ActionDesc.OP_CONCAT:
                processConcatOperation(opCode, stack, result);
                break;

            default:
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "core.constraint.illegalop", // NOI18N
                        "" + opCode)); // NOI18N
        }
    }

    private void processConcatOperation(int opCode, List stack,
            StringBuffer result) {

        if (stack.size() < 2) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.stackempty")); // NOI18N
        }
        String concatCast = vendorType.getConcatCast();
        if (concatCast.length() != 0) {
            result.append(concatCast);
            //Opening brace for concat cast
            result.append("( "); // NOI18N
        }
        // Concat is a binary infix operator. Process it manually here.
        // Resolve: Why should CONCAT operation be inside braces.
        // Opening brace around CONCAT operation
        result.append("( "); // NOI18N
        result.append(getWhereText(stack));
        result.append(infixOperator(opCode, 0));
        result.append(getWhereText(stack));
        // Closing brace around CONCAT operation
        result.append(" ) "); // NOI18N

        if (concatCast.length() != 0) {
            // Closing brace for concat cast
            result.append(" ) "); // NOI18N
        }
    }

    private void processMaybeNullOperation(List stack, StringBuffer result) {
        ConstraintValue valueNode = null;
        ConstraintField fieldNode = null;

        if (stack.size() < 2) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.stackempty")); // NOI18N
        }

        if (!(stack.get(stack.size() - 1) instanceof ConstraintField)) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.needfieldnode")); // NOI18N
        } else {
            fieldNode = (ConstraintField) stack.get(stack.size() - 1);
            stack.remove(stack.size() - 1);
        }

        if (!(stack.get(stack.size() - 1) instanceof ConstraintValue)) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.needvalnode")); // NOI18N
        } else {
            valueNode = (ConstraintValue) stack.get(stack.size() - 1);
            stack.remove(stack.size() - 1);
        }

        Object value = valueNode.getValue();
        if (value instanceof String) {
            String v = (String) value;

            if (v.length() == 0) {
                stack.add(fieldNode);
                stack.add(new ConstraintOperation(ActionDesc.OP_NULL));
            } else {
                stack.add(valueNode);
                stack.add(fieldNode);
                stack.add(new ConstraintOperation(ActionDesc.OP_EQ));
            }
        } else {
            stack.add(valueNode);
            stack.add(fieldNode);
            stack.add(new ConstraintOperation(ActionDesc.OP_EQ));

            //
            // This takes care of the case where a nullable database column
            // is mapped to a primitive field.
            // This check adds a "OR numericColumn IS NULL" to the constraint.
            // See FieldDesc#setValue(StateManager, Object) for the conversions
            // done on binding a primitive field from the store.
            //
            // RESOLVE: Don't we have to do this in each OP_EQ comparison
            // involving primitive Fields?
            //
            boolean maybeNull = false;

            if ((value instanceof Number) &&
                    ((Number) value).doubleValue() == 0) {
                maybeNull = true;
            } else if ((value instanceof Boolean) &&
                    ((Boolean) value).booleanValue() == false) {
                maybeNull = true;
            } else if ((value instanceof Character) &&
                    ((Character) value).charValue() == '\0') {
                maybeNull = true;
            }

            if (maybeNull) {
                stack.add(fieldNode);
                stack.add(new ConstraintOperation(ActionDesc.OP_NULL));
                stack.add(new ConstraintOperation(ActionDesc.OP_OR));
            }
        }

        if (stack.size() > 0) {
            result.append(getWhereText(stack));
        }
    }

    private void processNullOperation(int opCode, List stack, StringBuffer result) {
        String nullComparisionFunctionName =
            vendorType.getNullComparisonFunctionName();
        if( nullComparisionFunctionName.length() != 0) {
            // Null comparision for LOB type fields is
            // through function for this DB
            Object nextNode = stack.get(stack.size() - 1);
            if( nextNode != null) {
                if ( nextNode instanceof ConstraintFieldName) {
                    ConstraintFieldName fieldNode =
                            (ConstraintFieldName) nextNode;
                    QueryPlan originalPlan = getQueryPlan();
                    if (fieldNode.originalPlan != null) {
                        originalPlan = fieldNode.originalPlan;
                    }
                    LocalFieldDesc desc = (LocalFieldDesc) originalPlan.config.getField(fieldNode.name);
                    if ( desc.isMappedToLob() ) {
                        // Add a dummy ConstraintOperation Node corresponding
                        // to null comparision func.
                        stack.add (new ConstraintOperation(
                                ActionDesc.OP_NULL_COMPARISION_FUNCTION) );
                    }
                }
            } else {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.stackempty")); // NOI18N
           }
        }
        result.append (getWhereText(stack));
        String str = (opCode == ActionDesc.OP_NULL) ? vendorType.getIsNull() : vendorType.getIsNotNull();
        result.append(str);
    }

    private void processInOperation(int opCode, List stack, StringBuffer result) {
        //We are trying to construct a where clause like following in the quotes here
        // where "(t0.field1, t0.field2, t0.field3,...) in
        //        ( select t1.fld1, t1.fld2, t2.fld3,...where ....)"

        StringBuffer c = new StringBuffer();

        if (stack.size() < 2) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.stackempty")); // NOI18N
        }

        //Append the first bracket "(" to the result
        result.append("("); // NOI18N

        if (!(stack.get(stack.size() - 1) instanceof ConstraintField)) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.needfieldnode")); // NOI18N
        } else {
            //append "t0.field1" to c
            c.append(getWhereText(stack));
        }

        //Append ", t0.field2, t0fld3,...."
        while (stack.size() > 1 && (stack.get(stack.size() - 1) instanceof ConstraintField)) {
            c.replace(0, 0, ", "); // NOI18N
            c.replace(0, 0, getWhereText(stack));
        }
        result.append(c.toString());
        result.append(") "); // NOI18N
        if (opCode == ActionDesc.OP_NOTIN) {
            result.append("not "); // NOI18N
        }
        result.append("in ("); // NOI18N


        ConstraintNode currentNode = (ConstraintNode)stack.remove(stack.size() - 1);
        if ( ! ( currentNode instanceof ConstraintSubquery)) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.generic.notinstanceof", // NOI18N
                    currentNode.getClass().getName(), "ConstraintSubquery")); // NOI18N
        } else {

            ConstraintSubquery sqnode = (ConstraintSubquery) currentNode;

            Statement sqstmt = (Statement) sqnode.plan.statements.get(0);
            //Append the subquery i.e. "select t1.fld1, t1.fld2, t2.fld3,...where ...."
            result.append(sqstmt.getText());

            //Close the final bracket
            result.append(")"); // NOI18N

            //Append the Input values to the InputDesc of current statement
            inputDesc.values.addAll(sqstmt.inputDesc.values);
        }

        /*
          //This is old code that takes care of case when we just have a list of values
          //as the parameter to the IN clause. We might uncomment and enhance this code
          //when we implement the functionality to have list of values inside IN clause.
        if (!(stack.get(stack.size() - 1) instanceof ConstraintValue)) {
            throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.constraint.needvalnode")); // NOI18N
        } else {
            result.append(((ConstraintValue) stack.get(stack.size() - 1)).value.toString());
            stack.remove(stack.size() - 1);
        }

        result.append(")"); // NOI18N
        */
    }

    /**
     * Gets the column information for the field to which <code>node
     * is bound.
     * @param node The input node.
     * @return Returns null if the node isn't bound to a field. Otherwise
     * returns ColumnElement for the primary column of the field to which the
     * node is bound.
     */
    private static ColumnElement getColumnElementForValueNode(ConstraintValue node) {
        ColumnElement columnElement = null;
        LocalFieldDesc field = node.getLocalField();
        if(field != null) {
            //For fields mapped to multiple columns, we assume
            //that all the columns have the same value in the database.
            //Hence we only use the primary column in where clause.
            columnElement = field.getPrimaryColumn();
        }
        return columnElement;
    }

    /**
     * Generates InputValue for <code>node.
     * @param node The input node.
     */
    protected void generateInputValueForConstraintValueNode(ConstraintValue node) {
        inputDesc.values.add(new InputValue(node.getValue(), getColumnElementForValueNode(node) ));
    }

    //only operations end with ")" or nothing can be here, cf. getWhereText
    protected String infixOperator(int operation, int position) {
        //
        //	InfixOperator
        //		The InfixOperator method returns the SQL text for the operator specified
        //		by the operation parameter.
        //
        //	operation
        //		The operation parameter specifies which operation for which to return
        //		SQL text.  Legal values are defined by the ConstraintOperation class.
        //
        StringBuffer result = new StringBuffer();

        switch (operation) {
            case ActionDesc.OP_ADD:
                result.append(" + "); // NOI18N
                break;
            case ActionDesc.OP_AND:
                result.append(" and ");
                break;
            case ActionDesc.OP_DIV:
                result.append(" / "); // NOI18N
                break;
            case ActionDesc.OP_EQ:
                result.append(" = "); // NOI18N
                break;
            case ActionDesc.OP_GE:
                result.append(" >= "); // NOI18N
                break;
            case ActionDesc.OP_GT:
                result.append(" > "); // NOI18N
                break;
            case ActionDesc.OP_LE:
                result.append(" <= "); // NOI18N
                break;
            case ActionDesc.OP_LT:
                result.append(" < "); // NOI18N
                break;
            case ActionDesc.OP_NE:
                result.append(" ");
                result.append(vendorType.getNotEqual());
                result.append(" ");
                break;
            case ActionDesc.OP_OR:
                result.append(" or "); // NOI18N
                break;
            case ActionDesc.OP_LIKE:
                result.append(" like "); // NOI18N
                break;
            case ActionDesc.OP_MUL:
                result.append(" * "); // NOI18N
                break;
            case ActionDesc.OP_SUB:
                result.append(" - "); // NOI1N8
                break;
            case ActionDesc.OP_MOD:
                result.append(" % "); // NOI1N8
                break;
            case ActionDesc.OP_BETWEEN:
                if (position == 1) {
                    result.append(" between "); // NOI18N
                } else {
                    result.append(" and ");
                }
                break;
            case ActionDesc.OP_CONCAT:
                result.append(vendorType.getStringConcat());
                break;
            default:
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "core.constraint.illegalop", // NOI18N
                        "" + operation)); // NOI18N
        }

        return result.toString();
    }


    protected int operationFormat(int operation) {
        int format = 0;
        switch (operation) {
            // Binary operators
            case ActionDesc.OP_EQ:
            case ActionDesc.OP_NE:
            case ActionDesc.OP_GT:
            case ActionDesc.OP_GE:
            case ActionDesc.OP_LT:
            case ActionDesc.OP_LE:
            case ActionDesc.OP_AND:
            case ActionDesc.OP_MUL:
            case ActionDesc.OP_LIKE:
                format = OP_BINOP_MASK;
                break;

            // Binary operators that require Parenthesis
            case ActionDesc.OP_ADD:
            case ActionDesc.OP_SUB:
            case ActionDesc.OP_DIV:
            case ActionDesc.OP_OR:
                format = OP_BINOP_MASK | OP_PAREN_MASK;
                break;

            // Functions
            case ActionDesc.OP_ABS:
            case ActionDesc.OP_SQRT:
            case ActionDesc.OP_LENGTH:
            case ActionDesc.OP_LTRIM:
            case ActionDesc.OP_NOT:
            case ActionDesc.OP_NULL_COMPARISION_FUNCTION:
                format = OP_FUNC_MASK;
                break;

            // Irregular operators
            case ActionDesc.OP_BETWEEN:
            case ActionDesc.OP_LIKE_ESCAPE:
            case ActionDesc.OP_IN:
            case ActionDesc.OP_NOTIN:
            case ActionDesc.OP_NULL:
            case ActionDesc.OP_NOTNULL:
            case ActionDesc.OP_MAYBE_NULL:
            case ActionDesc.OP_CONCAT:
            case ActionDesc.OP_EQUIJOIN:
                format = OP_IRREGULAR_MASK | OP_WHERE_MASK;
                break;

            // Irregular operators that can never be at the root of a where clause.
            // Hence they do not have OP_WHERE_MASK set.
            case ActionDesc.OP_SUBSTRING:
            case ActionDesc.OP_POSITION:
            case ActionDesc.OP_POSITION_START:
                format = OP_IRREGULAR_MASK;
                break;

            case ActionDesc.OP_NOTEXISTS:
            case ActionDesc.OP_EXISTS:
                format = OP_IRREGULAR_MASK | OP_WHERE_MASK | OP_PREFIX_MASK;
                break;

            case ActionDesc.OP_MOD:
                format = vendorType.isModOperationUsingFunction() ?
                    OP_IRREGULAR_MASK : OP_BINOP_MASK | OP_PAREN_MASK;
                break;

            case ActionDesc.OP_DISTINCT:
                format = OP_OTHER_MASK;
                break;

            case ActionDesc.OP_ORDERBY:
            case ActionDesc.OP_ORDERBY_DESC:
                format = OP_ORDERBY_MASK;
                break;

            case ActionDesc.OP_RTRIM:
            case ActionDesc.OP_RTRIMFIXED:
                if (vendorType.isAnsiTrim()) {
                    format = OP_WHERE_MASK | OP_PREFIX_MASK | OP_POSTFIX_MASK | OP_PARAM_MASK;
                } else {
                    format = OP_FUNC_MASK;
                }
                break;

            //TODO: Check how can this masks be optimized
            case ActionDesc.OP_LEFTJOIN:
                format = OP_IRREGULAR_MASK | OP_WHERE_MASK | OP_INFIX_MASK;
                format = format | OP_POSTFIX_MASK;
                break;
            case ActionDesc.OP_RIGHTJOIN:
                format = OP_IRREGULAR_MASK | OP_WHERE_MASK | OP_INFIX_MASK;
                format = format | OP_PREFIX_MASK;
                break;

            default:
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "core.constraint.illegalop", // NOI18N
                        "" + operation)); // NOI18N
        }

        return format;
    }

    protected String postfixOperator(int operation) {
        //
        //	PostfixOperator
        //		The PostfixOperator method returns the SQL text for the operator specified
        //		by the operation parameter.
        //
        //	operation
        //		The operation parameter specifies which operation for which to return
        //		SQL text.  Legal values are defined by the ConstraintOperation class.
        //
        StringBuffer result = new StringBuffer();

        switch (operation) {
            case ActionDesc.OP_RTRIM:
                result.append(vendorType.getRtrimPost());
                break;
            case ActionDesc.OP_RTRIMFIXED:
                result.append(postfixOperator(ActionDesc.OP_RTRIM));
                break;
            case ActionDesc.OP_LEFTJOIN:
                result.append(vendorType.getLeftJoinPost());
                break;
            default:
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "core.constraint.illegalop", // NOI18N
                        "" + operation)); // NOI18N
        }

        return result.toString();
    }

    protected String prefixOperator(int operation) {
        //
        //  PrefixOperator
        //      The PrefixOperator method returns the SQL text for the operator specified
        //      by the operation parameter.
        //
        //  operation
        //      The operation parameter specifies which operation for which to return
        //      SQL text.  Legal values are defined by the ConstraintOperation class.
        //
        StringBuffer result = new StringBuffer();

        switch (operation) {
            case ActionDesc.OP_ABS:
                result.append(vendorType.getAbs()); // NOI18N
                break;
            case ActionDesc.OP_LENGTH:
                result.append(vendorType.getCharLength()); // NOI18N
                break;
            case ActionDesc.OP_RTRIM:
                result.append(vendorType.getRtrim());
                break;
            case ActionDesc.OP_RTRIMFIXED:
                result.append(prefixOperator(ActionDesc.OP_RTRIM));
                break;
            case ActionDesc.OP_NOT:
                result.append("not "); // NOI18N
                break;
            case ActionDesc.OP_SQRT:
                result.append(vendorType.getSqrt());
                break;
            case ActionDesc.OP_NOTEXISTS:
                result.append("not exists "); // NOI18N
                break;
            case ActionDesc.OP_EXISTS:
                result.append("exists "); // NOI18N
                break;
            case ActionDesc.OP_NULL_COMPARISION_FUNCTION:
                result.append(vendorType.getNullComparisonFunctionName());
                break;
            case ActionDesc.OP_MOD:
                result.append(vendorType.getModFunctionName()); // NOI18N
                break;

            default:
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "core.constraint.illegalop", "" + operation)); // NOI18N
        }

        return result.toString();
    }

    public void addSecondaryTableStatement(Statement s) {
        if (s == null) return;

        if (secondaryTableStatements == null)
            secondaryTableStatements = new ArrayList();

        secondaryTableStatements.add(s);
    }

    public ArrayList getSecondaryTableStatements() {
        return secondaryTableStatements;
    }

    public ArrayList getQueryTables() {
        return tableList;
    }

    public ArrayList getColumnRefs() {
        return columns;
    }

    public void setAction(int action) {
        this.action = action;
    }

    public int getAction() {
        return action;
    }

    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            //
            // shouldn't happen.
            //
            return null;
        }
    }

    /**
     * Binds input valus corrsponding to this <code>Statement object to
     * database statement s.
     * @param s The database statement
     * @throws SQLException
     */
    public void bindInputValues(DBStatement s) throws SQLException {
        for (int i = 0, size = inputDesc.values.size(); i < size; i++) {
            InputValue inputVal = (InputValue) inputDesc.values.get(i);
            s.bindInputColumn(i + 1, inputVal.getValue(),
                    inputVal.getColumnElement(), vendorType);
        }
    }

    /**
     * Gets input values corrsponding to this <code>Statement.
     * @return An Object array containing input values.
     */
    private Object[] getInputValues() {
        final int size = inputDesc.values.size();
        Object[] inputValues = new Object[size];
        for (int i = 0; i < size; i++) {
            InputValue inputValue = (InputValue) inputDesc.values.get(i);
            inputValues[i] = inputValue.getValue();
        }
        return inputValues;
    }

    /**
     * Gets formatted sql text corrsponding to this statement object. The text
     * also contains values for input to the statement.
     * @return formatted sql text corrsponding to this statement object.
     */
    public String getFormattedSQLText() {
        return formatSqlText(getText(), getInputValues());
    }

    /**
     *  The formatSqlText method returns a string containing the text of
     *  the SQL statement about to be executed and the input values for the
     *  placeholders.
     *  @param sqlText Specifies the text of the SQL statement to be executed.
     *  @param input Holds the input values used for the SQL statement.
     *  @return The SQL text and the input values formatted into a printable
     * string.
     */
    static protected String formatSqlText(String sqlText, Object[] input) {
        StringBuffer str = new StringBuffer();

        str.append(I18NHelper.getMessage(messages,
                "sqlstore.sql.generator.statement.sqlStatement") );   //NOI18N
        str.append("<").append(sqlText).append("> "); // NOI18N

        if (input != null && input.length > 0) {
            str.append(I18NHelper.getMessage(messages,
            "sqlstore.sql.generator.statement.withinputvalues")); // NOI18N
            for (int i = 0; i < input.length; i++) {
                if (i > 0) {
                    str.append(", "); // NOI18N
                }
                Object inputValue = input[i];
                if (inputValue == null) {
                    str.append("<null>"); // NOI18N
                } else {
                    str.append(inputValue.getClass().getName());
                    str.append(":"); // NOI18N
                    str.append(inputValue.toString());
                }
            }
        } else {
            str.append(I18NHelper.getMessage(messages,
            "sqlstore.sql.generator.statement.withnoinputvalues")); // NOI18N
       }

        return str.toString();
    }

}

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish Statement.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.