Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : */
9 :
10 : #include "Columns.hxx"
11 : #include "Indexes.hxx"
12 : #include "Keys.hxx"
13 : #include "Table.hxx"
14 :
15 : #include <TConnection.hxx>
16 :
17 : #include <comphelper/sequence.hxx>
18 : #include <connectivity/dbtools.hxx>
19 :
20 : #include <com/sun/star/sdbc/ColumnValue.hpp>
21 : #include <com/sun/star/sdbcx/Privilege.hpp>
22 :
23 : using namespace ::connectivity;
24 : using namespace ::connectivity::firebird;
25 : using namespace ::connectivity::sdbcx;
26 :
27 : using namespace ::osl;
28 : using namespace ::rtl;
29 :
30 : using namespace ::com::sun::star;
31 : using namespace ::com::sun::star::beans;
32 : using namespace ::com::sun::star::container;
33 : using namespace ::com::sun::star::sdbc;
34 : using namespace ::com::sun::star::sdbcx;
35 : using namespace ::com::sun::star::uno;
36 :
37 0 : Table::Table(Tables* pTables,
38 : Mutex& rMutex,
39 : const uno::Reference< XConnection >& rConnection):
40 : OTableHelper(pTables,
41 : rConnection,
42 : true),
43 : m_rMutex(rMutex),
44 0 : m_nPrivileges(0)
45 : {
46 0 : construct();
47 0 : }
48 :
49 0 : Table::Table(Tables* pTables,
50 : Mutex& rMutex,
51 : const uno::Reference< XConnection >& rConnection,
52 : const OUString& rName,
53 : const OUString& rType,
54 : const OUString& rDescription):
55 : OTableHelper(pTables,
56 : rConnection,
57 : true,
58 : rName,
59 : rType,
60 : rDescription,
61 : "",
62 : ""),
63 : m_rMutex(rMutex),
64 0 : m_nPrivileges(0)
65 : {
66 0 : construct();
67 0 : }
68 :
69 0 : void Table::construct()
70 : {
71 0 : OTableHelper::construct();
72 0 : if (!isNew())
73 : {
74 : // TODO: get privileges when in non-embedded mode.
75 : m_nPrivileges = Privilege::DROP |
76 : Privilege::REFERENCE |
77 : Privilege::ALTER |
78 : Privilege::CREATE |
79 : Privilege::READ |
80 : Privilege::DELETE |
81 : Privilege::UPDATE |
82 : Privilege::INSERT |
83 0 : Privilege::SELECT;
84 0 : registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRIVILEGES),
85 : PROPERTY_ID_PRIVILEGES,
86 : PropertyAttribute::READONLY,
87 : &m_nPrivileges,
88 0 : ::getCppuType(&m_nPrivileges));
89 : }
90 0 : }
91 : //----- OTableHelper ---------------------------------------------------------
92 0 : OCollection* Table::createColumns(const TStringVector& rNames)
93 : {
94 : return new Columns(*this,
95 : m_rMutex,
96 0 : rNames);
97 : }
98 :
99 0 : OCollection* Table::createKeys(const TStringVector& rNames)
100 : {
101 : return new Keys(this,
102 : m_rMutex,
103 0 : rNames);
104 : }
105 :
106 0 : OCollection* Table::createIndexes(const TStringVector& rNames)
107 : {
108 : return new Indexes(this,
109 : m_rMutex,
110 0 : rNames);
111 : }
112 :
113 : //----- XAlterTable -----------------------------------------------------------
114 0 : void SAL_CALL Table::alterColumnByName(const OUString& rColName,
115 : const uno::Reference< XPropertySet >& rDescriptor)
116 : throw(SQLException, NoSuchElementException, RuntimeException, std::exception)
117 : {
118 0 : MutexGuard aGuard(m_rMutex);
119 0 : checkDisposed(WeakComponentImplHelperBase::rBHelper.bDisposed);
120 :
121 0 : uno::Reference< XPropertySet > xColumn(m_pColumns->getByName(rColName), UNO_QUERY);
122 :
123 : // sdbcx::Descriptor
124 0 : const bool bNameChanged = xColumn->getPropertyValue("Name") != rDescriptor->getPropertyValue("Name");
125 : // sdbcx::ColumnDescriptor
126 0 : const bool bTypeChanged = xColumn->getPropertyValue("Type") != rDescriptor->getPropertyValue("Type");
127 0 : const bool bTypeNameChanged = xColumn->getPropertyValue("TypeName") != rDescriptor->getPropertyValue("TypeName");
128 0 : const bool bPrecisionChanged = xColumn->getPropertyValue("Precision") != rDescriptor->getPropertyValue("Precision");
129 0 : const bool bScaleChanged = xColumn->getPropertyValue("Scale") != rDescriptor->getPropertyValue("Scale");
130 0 : const bool bIsNullableChanged = xColumn->getPropertyValue("IsNullable") != rDescriptor->getPropertyValue("IsNullable");
131 0 : const bool bIsAutoIncrementChanged = xColumn->getPropertyValue("IsAutoIncrement") != rDescriptor->getPropertyValue("IsAutoIncrement");
132 : // TODO: remainder -- these are all "optional" so have to detect presence and change.
133 :
134 0 : bool bDefaultChanged = xColumn->getPropertyValue("DefaultValue")
135 0 : != rDescriptor->getPropertyValue("DefaultValue");
136 :
137 : // TODO: quote identifiers as needed.
138 0 : if (bNameChanged)
139 : {
140 0 : OUString sNewTableName;
141 0 : rDescriptor->getPropertyValue("Name") >>= sNewTableName;
142 : OUString sSql(getAlterTableColumn(rColName)
143 0 : + " TO \"" + sNewTableName + "\"");
144 :
145 0 : getConnection()->createStatement()->execute(sSql);
146 : }
147 :
148 0 : if (bTypeChanged || bTypeNameChanged || bPrecisionChanged || bScaleChanged)
149 : {
150 : // If bPrecisionChanged this will only succeed if we have increased the
151 : // precision, otherwise an exception is thrown -- however the base
152 : // gui then offers to delete and recreate the column.
153 0 : OUString sSql(getAlterTableColumn(rColName) + "TYPE " +
154 0 : ::dbtools::createStandardTypePart(rDescriptor, getConnection()));
155 0 : getConnection()->createStatement()->execute(sSql);
156 : // TODO: could cause errors e.g. if incompatible types, deal with them here as appropriate.
157 : // possibly we have to wrap things in Util::evaluateStatusVector.
158 : }
159 :
160 0 : if (bIsNullableChanged)
161 : {
162 0 : sal_Int32 nNullabble = 0;
163 0 : rDescriptor->getPropertyValue("IsNullable") >>= nNullabble;
164 :
165 0 : if (nNullabble != ColumnValue::NULLABLE_UNKNOWN)
166 : {
167 :
168 0 : OUString sSql;
169 : // Dirty hack: can't change null directly in sql, we have to fiddle
170 : // the system tables manually.
171 0 : if (nNullabble == ColumnValue::NULLABLE)
172 : {
173 0 : sSql = "UPDATE RDB$RELATION_FIELDS SET RDB$NULL_FLAG = NULL "
174 0 : "WHERE RDB$FIELD_NAME = '" + rColName + "' "
175 0 : "AND RDB$RELATION_NAME = '" + getName() + "'";
176 : }
177 0 : else if (nNullabble == ColumnValue::NO_NULLS)
178 : {
179 : // And if we are making NOT NULL then we have to make sure we have
180 : // no nulls left in the column.
181 0 : OUString sFillNulls("UPDATE \"" + getName() + "\" SET \""
182 0 : + rColName + "\" = 0 "
183 0 : "WHERE \"" + rColName + "\" IS NULL");
184 0 : getConnection()->createStatement()->execute(sFillNulls);
185 :
186 0 : sSql = "UPDATE RDB$RELATION_FIELDS SET RDB$NULL_FLAG = 1 "
187 0 : "WHERE RDB$FIELD_NAME = '" + rColName + "' "
188 0 : "AND RDB$RELATION_NAME = '" + getName() + "'";
189 : }
190 0 : getConnection()->createStatement()->execute(sSql);
191 : }
192 : else
193 : {
194 : SAL_WARN("connectivity.firebird", "Attempting to set Nullable to NULLABLE_UNKNOWN");
195 : }
196 : }
197 :
198 : if (bIsAutoIncrementChanged)
199 : {
200 : // TODO: changeType
201 : }
202 :
203 0 : if (bDefaultChanged)
204 : {
205 0 : OUString sOldDefault, sNewDefault;
206 0 : xColumn->getPropertyValue("DefaultValue") >>= sOldDefault;
207 0 : rDescriptor->getPropertyValue("DefaultValue") >>= sNewDefault;
208 :
209 0 : OUString sSql;
210 0 : if (sNewDefault.isEmpty())
211 0 : sSql = getAlterTableColumn(rColName) + "DROP DEFAULT";
212 : else
213 0 : sSql = getAlterTableColumn(rColName) + "SET DEFAULT " + sNewDefault;
214 :
215 0 : getConnection()->createStatement()->execute(sSql);
216 : }
217 :
218 0 : m_pColumns->refresh();
219 0 : }
220 :
221 : // ----- XRename --------------------------------------------------------------
222 0 : void SAL_CALL Table::rename(const OUString& rName)
223 : throw(SQLException, ElementExistException, RuntimeException, std::exception)
224 : {
225 : (void) rName;
226 0 : throw RuntimeException(); // Firebird doesn't support this.
227 : }
228 :
229 : // ----- XInterface -----------------------------------------------------------
230 0 : Any SAL_CALL Table::queryInterface(const Type& rType)
231 : throw(RuntimeException, std::exception)
232 : {
233 0 : if (rType.getTypeName() == "com.sun.star.sdbcx.XRename")
234 0 : return Any();
235 :
236 0 : return OTableHelper::queryInterface(rType);
237 : }
238 :
239 : // ----- XTypeProvider --------------------------------------------------------
240 0 : uno::Sequence< Type > SAL_CALL Table::getTypes()
241 : throw(RuntimeException, std::exception)
242 : {
243 0 : uno::Sequence< Type > aTypes = OTableHelper::getTypes();
244 :
245 0 : for (int i = 0; i < aTypes.getLength(); i++)
246 : {
247 0 : if (aTypes[i].getTypeName() == "com.sun.star.sdbcx.XRename")
248 : {
249 0 : ::comphelper::removeElementAt(aTypes, i);
250 0 : break;
251 : }
252 : }
253 :
254 0 : return OTableHelper::getTypes();
255 : }
256 :
257 0 : OUString Table::getAlterTableColumn(const OUString& rColumn)
258 : {
259 0 : return ("ALTER TABLE \"" + getName() + "\" ALTER COLUMN \"" + rColumn + "\" ");
260 : }
261 :
262 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|