source: main/trunk/greenstone2/common-src/src/lib/dbclass.cpp@ 28732

Last change on this file since 28732 was 28732, checked in by ak19, 10 years ago

Diego found a bug that crashed the server in his collection which set the OIDtype to incremental and used a classifier on dc.Subject meta. When the OIDs generated were too short, such as happens when maxdocs is low or the number of docs in the collection is low, the server crashes. Have now added a test in the dbclass.cpp code that ensures we don't substring the OID's tail if this is too short for the substring operation. This now works with Diego's collection which used to crash for me before.

File size: 8.3 KB
Line 
1/**********************************************************************
2 *
3 * dbclass.cpp --
4 * Copyright (C) 1999-2008 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include "dbclass.h"
27#include "OIDtools.h"
28#include "unitool.h"
29
30
31dbclass::~dbclass() {}
32
33
34// May be overwritten by subclasses; returns true if exists
35bool dbclass::exists (const text_t& key)
36{
37 text_t data;
38 return getkeydata (key, data);
39}
40
41
42// May be overwritten by subclasses; returns true on success
43bool dbclass::getinfo (const text_t& key, infodbclass &info)
44{
45 text_t data;
46 if (!getkeydata(key, data)) return false;
47
48 // Use getinfoline() to parse the data value into the infodbclass object
49 text_t::iterator data_iterator = data.begin();
50 text_t ikey, ivalue;
51 info.clear();
52 while (getinfoline(data_iterator, data.end(), ikey, ivalue))
53 {
54 info.addinfo(ikey, ivalue);
55 }
56
57 return true;
58}
59
60
61// returns true on success
62bool dbclass::getinfoline (text_t::iterator &here, text_t::iterator end,
63 text_t &key, text_t &value)
64{
65 key.clear();
66 value.clear();
67
68 // ignore white space
69 while (here != end && is_unicode_space (*here)) ++here;
70
71 // get the '<'
72 if (here == end || *here != '<') return false;
73 ++here;
74
75 // get the key
76 while (here != end && *here != '>') {
77 key.push_back(*here);
78 ++here;
79 }
80
81 // get the '>'
82 if (here == end || *here != '>') return false;
83 ++here;
84
85 // get the value
86 while (here != end && *here != '\n') {
87 if (*here == '\\') {
88 // found escape character
89 ++here;
90 if (here != end) {
91 if (*here == 'n') value.push_back ('\n');
92 else if (*here == 'r') value.push_back ('\r');
93 else value.push_back(*here);
94 }
95
96 } else {
97 if(*here != '\r') {
98 // a normal character
99 value.push_back(*here);
100 }
101 }
102
103 ++here;
104 }
105
106 return true;
107}
108
109
110// returns true on success
111bool dbclass::setinfo (const text_t &key, const infodbclass &info)
112{
113 text_t subkey;
114 text_t data;
115
116 // get all the keys and values
117 infodbclass::const_iterator info_here = info.begin();
118 infodbclass::const_iterator info_end = info.end();
119 while (info_here != info_end) {
120 // add the key
121 subkey.clear();
122 subkey.push_back('<');
123 text_t::const_iterator subkey_here = (*info_here).first.begin();
124 text_t::const_iterator subkey_end = (*info_here).first.end();
125 while (subkey_here != subkey_end) {
126 if (*subkey_here == '>') {
127 subkey.push_back('\\'); subkey.push_back('>');
128 } else if (*subkey_here == '\n') {
129 subkey.push_back('\\'); subkey.push_back('n');
130 } else if (*subkey_here == '\r') {
131 subkey.push_back('\\'); subkey.push_back('r');
132 } else if (*subkey_here == '\\') {
133 subkey.push_back('\\'); subkey.push_back('\\');
134 } else {
135 subkey.push_back (*subkey_here);
136 }
137 ++subkey_here;
138 }
139 subkey.push_back('>');
140
141 // add the values
142 text_tarray::const_iterator subvalue_here = (*info_here).second.begin();
143 text_tarray::const_iterator subvalue_end = (*info_here).second.end();
144 while (subvalue_here != subvalue_end) {
145 data += subkey;
146
147 text_t::const_iterator thissubvalue_here = (*subvalue_here).begin();
148 text_t::const_iterator thissubvalue_end = (*subvalue_here).end();
149 while (thissubvalue_here != thissubvalue_end) {
150 if (*thissubvalue_here == '>') {
151 data.push_back('\\'); data.push_back('>');
152 } else if (*thissubvalue_here == '\n') {
153 data.push_back('\\'); data.push_back('n');
154 } else if (*thissubvalue_here == '\r') {
155 data.push_back('\\'); data.push_back('r');
156 } else if (*thissubvalue_here == '\\') {
157 data.push_back('\\'); data.push_back('\\');
158 } else {
159 data.push_back (*thissubvalue_here);
160 }
161
162 ++thissubvalue_here;
163 }
164
165 data.push_back('\n');
166 ++subvalue_here;
167 }
168
169 ++info_here;
170 }
171
172 return setkeydata(key, data);
173}
174
175
176// replaces the .fc, .lc, .pr, .rt, .ns and .ps syntax (first child,
177// last child, parent, root, next sibling, previous sibling)
178// it expects child, parent, etc. to exist if syntax has been used
179// so you should test before using
180text_t dbclass::translate_OID (const text_t &inOID, infodbclass &info)
181{
182 if (inOID.size() < 4) return inOID;
183 if (findchar (inOID.begin(), inOID.end(), '.') == inOID.end()) return inOID;
184
185 text_t OID = inOID;
186 text_tarray tailarray;
187 text_t tail = substr (OID.end()-3, OID.end());
188 if (tail == ".rt") {
189 get_top (inOID, OID);
190 return OID;
191 }
192 while (tail == ".fc" || tail == ".lc" || tail == ".pr" ||
193 tail == ".ns" || tail == ".ps") {
194 tailarray.push_back(tail);
195 OID.erase (OID.end()-3, OID.end());
196
197 if(OID.size() <= 3) {
198 break;
199 } else {
200 tail = substr (OID.end()-3, OID.end());
201 }
202 if (tail == ".rt") {
203 get_top (inOID, OID);
204 return OID;
205 }
206 }
207
208 if (tailarray.empty()) return inOID;
209 text_tarray::const_iterator begin = tailarray.begin();
210 text_tarray::const_iterator here = tailarray.end() - 1;
211
212 while (here >= begin) {
213
214 if (*here == ".fc")
215 get_first_child (OID, info);
216 else if (*here == ".lc")
217 get_last_child (OID, info);
218 else if (*here == ".pr")
219 OID = get_parent (OID);
220 else if (*here == ".ns")
221 get_next_sibling (OID, info);
222 else if (*here == ".ps")
223 get_previous_sibling (OID, info);
224
225 if (here == begin)
226 break;
227 --here;
228 }
229
230 return OID;
231}
232
233
234void dbclass::get_first_child (text_t &OID, infodbclass &info)
235{
236 text_t firstchild;
237 if (getinfo (OID, info)) {
238 text_t &contains = info["contains"];
239 if (!contains.empty()) {
240 text_t parent = OID;
241 getdelimitstr (contains.begin(), contains.end(), ';', firstchild);
242 if (firstchild.empty()) OID = contains;
243 else OID = firstchild;
244 if (*(OID.begin()) == '"') translate_parent (OID, parent);
245 }
246 }
247}
248
249
250void dbclass::get_last_child (text_t &OID, infodbclass &info)
251{
252 text_tarray children;
253 if (getinfo (OID, info)) {
254 text_t &contains = info["contains"];
255 if (!contains.empty()) {
256 text_t parent = OID;
257 splitchar (contains.begin(), contains.end(), ';', children);
258 OID = children.back();
259 if (*(OID.begin()) == '"') translate_parent (OID, parent);
260 }
261 }
262}
263
264
265void dbclass::get_next_sibling (text_t &OID, infodbclass &info)
266{
267 text_tarray siblings;
268 text_t parent = get_parent (OID);
269
270 if (getinfo (parent, info)) {
271 text_t &contains = info["contains"];
272 if (!contains.empty()) {
273 splitchar (contains.begin(), contains.end(), ';', siblings);
274 text_tarray::const_iterator here = siblings.begin();
275 text_tarray::const_iterator end = siblings.end();
276 text_t shrunk_OID = OID;
277 shrink_parent (shrunk_OID);
278 while (here != end) {
279 if (*here == shrunk_OID && (here+1 != end)) {
280 OID = *(here+1);
281 if (*(OID.begin()) == '"') translate_parent (OID, parent);
282 break;
283 }
284 ++here;
285 }
286 }
287 }
288}
289
290
291void dbclass::get_previous_sibling (text_t &OID, infodbclass &info)
292{
293 text_tarray siblings;
294 text_t parent = get_parent (OID);
295
296 if (getinfo (parent, info)) {
297 text_t &contains = info["contains"];
298 if (!contains.empty()) {
299 splitchar (contains.begin(), contains.end(), ';', siblings);
300 text_tarray::const_iterator here = siblings.begin();
301 text_tarray::const_iterator end = siblings.end();
302 text_t shrunk_OID = OID;
303 shrink_parent (shrunk_OID);
304 while (here != end) {
305 if (*here == shrunk_OID && (here != siblings.begin())) {
306 OID = *(here-1);
307 if (*(OID.begin()) == '"') translate_parent (OID, parent);
308 break;
309 }
310 ++here;
311 }
312 }
313 }
314}
Note: See TracBrowser for help on using the repository browser.