1 /*
2 Copyright (c) 2008 Health Market Science, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17 USA
18
19 You can contact Health Market Science at info@healthmarketscience.com
20 or at the following address:
21
22 Health Market Science
23 2700 Horizon Drive
24 Suite 200
25 King of Prussia, PA 19406
26 */
27
28 package com.healthmarketscience.sqlbuilder;
29
30 import com.healthmarketscience.common.util.AppendableExt;
31
32 /**
33 * Object which maintains context for the sqlbuilder classes when a SQL
34 * statement is being generated. The object is passed from one SqlObject to
35 * another via the {@link com.healthmarketscience.common.util.AppendableExt#setContext}
36 * and {@link com.healthmarketscience.common.util.AppendableExt#getContext} methods.
37 * This class enables the various SqlObject SQL generation methods to behave
38 * differently depending on where they are being used in a query.
39 *
40 * Note, users of the sqlbuilder classes may extend this context to pass
41 * through more information as any copying of SqlContexts is done via cloning.
42 * The custom context may be introduced to the current SQL generation context
43 * via the {@link SqlObject#toString(int,SqlContext)} method call.
44 *
45 * @author James Ahlborn
46 */
47 public class SqlContext implements Cloneable
48 {
49
50 /** Previous context replaced by this context, if any */
51 private SqlContext _parent;
52
53 /** flag indicating whether or not table aliases should be used in the
54 current SQL generation context */
55 private boolean _useTableAliases = true;
56
57 /** flag indicating whether constraints apply to a column or a table */
58 private boolean _useTableConstraints = true;
59
60 /** handle to the immediate wrapping query */
61 private Query<?> _query;
62
63 public SqlContext() {
64 }
65
66 /**
67 * Gets the SqlContext which was in effect before this SqlContext was
68 * "pushed" onto the context stack.
69 */
70 public SqlContext getParent() {
71 return _parent;
72 }
73
74 /**
75 * Sets the SqlContext which was in effect before this SqlContext was
76 * "pushed" onto the context stack. Used by {@link #pushContext}.
77 */
78 private void setParent(SqlContext newParentContext) {
79 _parent = newParentContext;
80 }
81
82 /**
83 * @return the flag indicating whether or not table aliases should be used
84 * in the current SQL generation context.
85 */
86 public boolean getUseTableAliases() {
87 return _useTableAliases;
88 }
89
90 /**
91 * Sets flag indicating whether or not table aliases should be used in the
92 * current SQL generation context.
93 */
94 public void setUseTableAliases(boolean newUseTableAliases) {
95 _useTableAliases = newUseTableAliases;
96 }
97
98 /**
99 * @return the flag indicating whether or not table constraints should be
100 * used in the current SQL generation context.
101 */
102 public boolean getUseTableConstraints() {
103 return _useTableConstraints;
104 }
105
106 /**
107 * Sets flag indicating whether or not table constraints should be used in
108 * the current SQL generation context.
109 */
110 public void setUseTableConstraints(boolean newUseTableConstraints) {
111 _useTableConstraints = newUseTableConstraints;
112 }
113
114 /**
115 * Gets the handle to the immediate wrapping query
116 */
117 public Query<?> getQuery() {
118 return _query;
119 }
120
121 /**
122 * Sets the handle to the immediate wrapping query
123 */
124 public void setQuery(Query<?> newQuery) {
125 _query = newQuery;
126 }
127
128 @Override
129 public SqlContext clone() {
130 try {
131 return (SqlContext)super.clone();
132 } catch(CloneNotSupportedException e) {
133 throw new RuntimeException("should never get here", e);
134 }
135 }
136
137 /**
138 * Gets the current SqlContext from the given AppendableExt, creating one if
139 * necessary. Should be used by any subclasses of SqlObject wishing to
140 * retrieve the current context.
141 */
142 public static SqlContext getContext(AppendableExt app)
143 {
144 SqlContext context = (SqlContext)app.getContext();
145 if(context == null) {
146 context = new SqlContext();
147 app.setContext(context);
148 }
149 return context;
150 }
151
152 /**
153 * Creates a new SqlContext (cloning current one if available), replaces the
154 * current SqlContext with the new SqlContext, and returns the new
155 * SqlContext. All <code>pushContext</code> calls should have a
156 * corresponding {@link #popContext} call.
157 */
158 public static final SqlContext pushContext(AppendableExt app)
159 {
160 SqlContext parentContext = (SqlContext)app.getContext();
161 SqlContext context = null;
162 if(parentContext != null) {
163 context = parentContext.clone();
164 context.setParent(parentContext);
165 } else {
166 context = new SqlContext();
167 }
168 app.setContext(context);
169 return context;
170 }
171
172 /**
173 * Replaces the current SqlContext (checking it against the given
174 * SqlContext) with the parent SqlContext (stored within the new one). All
175 * <code>popContext</code> calls should come after a corresponding
176 * {@link #pushContext} call.
177 */
178 public static void popContext(AppendableExt app, SqlContext context)
179 {
180 if(app.getContext() != context) {
181 throw new IllegalStateException("Mismatched push/pop SqlContext");
182 }
183 app.setContext((context != null) ? context.getParent() : null);
184 }
185
186
187 }