102 // If tokens are identical, handle as case 3, otherwise handle as case 4. |
102 // If tokens are identical, handle as case 3, otherwise handle as case 4. |
103 // ("10203" -> tokens "1" and "203" |
103 // ("10203" -> tokens "1" and "203" |
104 // "0010023004560" -> tokens "001" and "23004560") |
104 // "0010023004560" -> tokens "001" and "23004560") |
105 // |
105 // |
106 // 6: "10", "1000" |
106 // 6: "10", "1000" |
107 // Two tokens, last token ends zero. |
107 // One token, ends with zero. |
108 // In this case, query should look-up first toke and number ("10", "1000"). |
108 // In this case, query should look-up first toke and number ("10", "1000"). |
109 |
109 |
110 QString CntSqlSearch::CreatePredictiveSearch(const QString &pattern) |
110 QString CntSqlSearch::CreatePredictiveSearch(const QString &pattern) |
111 { |
111 { |
112 int len = pattern.length(); |
112 int len = pattern.length(); |
113 QString newPattern = ChangeStringPadings(pattern); |
113 QString newPattern = ChangeStringPadings(pattern); |
114 // For best performance, handle 1 digit case first |
114 // For best performance, handle 1 digit case first |
115 if (len == KMinimumSearchPatternLength) |
115 if (len == KMinimumSearchPatternLength) |
116 { |
116 { |
244 } |
244 } |
245 |
245 |
246 // pattern length is between KMinimumSearchPatternLength...KLimitLength |
246 // pattern length is between KMinimumSearchPatternLength...KLimitLength |
247 QString CntSqlSearch::CreateQuery(const QString& pattern) const |
247 QString CntSqlSearch::CreateQuery(const QString& pattern) const |
248 { |
248 { |
249 QStringList tokens = GetTokens(pattern); |
249 QStringList tokens = GetTokens(pattern); |
250 if (tokens.count() < KTwoTokens) |
250 if (tokens.count() < KTwoTokens) |
|
251 { |
|
252 if (TestPattern(pattern, CntSqlSearch::ZerosEndOfFirstToken)) |
251 { |
253 { |
252 if( TestPattern(pattern, CntSqlSearch::ZerosEndOfFirstToken)) |
254 return TwoDifferentTokensSearch(pattern, tokens); // Case 6 |
253 { |
|
254 return TwoDifferentTokensSearch(pattern, tokens); // Case 6 |
|
255 } |
|
256 else |
|
257 { |
|
258 return ExactMatchSearch(pattern) + Order(tokens); // Case 2 |
|
259 } |
|
260 } |
255 } |
|
256 else |
|
257 { |
|
258 return ExactMatchSearch(pattern) + Order(tokens); // Case 2 |
|
259 } |
|
260 } |
261 else |
261 else |
262 { |
262 { |
263 if (tokens.at(0) == tokens.at(1)) |
263 if (tokens.at(0) == tokens.at(1)) |
264 { |
264 { |
265 return IdenticalTokensSearch(pattern, tokens); // Case 3 |
265 return IdenticalTokensSearch(pattern, tokens); // Case 3 |
266 } |
|
267 else |
|
268 { |
|
269 return IntersectionSearch(pattern, tokens); // Case 4 |
|
270 } |
|
271 } |
266 } |
|
267 else |
|
268 { |
|
269 return IntersectionSearch(pattern, tokens); // Case 4 |
|
270 } |
|
271 } |
272 } |
272 } |
273 |
273 |
274 QString CntSqlSearch::ExactMatchSearch(const QString& pattern) const |
274 QString CntSqlSearch::ExactMatchSearch(const QString& pattern) const |
275 { |
275 { |
276 return QString(SELECT_CONTACT_ID + SelectTable(pattern) + |
276 return QString(SELECT_CONTACT_ID + SelectTable(pattern) + |
323 } |
323 } |
324 |
324 |
325 // Find the exact match, or a column whose value is within |
325 // Find the exact match, or a column whose value is within |
326 // lower..upper(exclusive) and another column whose value is within |
326 // lower..upper(exclusive) and another column whose value is within |
327 // lower2..upper2(exclusive). |
327 // lower2..upper2(exclusive). |
328 // In this case the limits are is different, so there are 12 combinations the |
328 // In this case the limits are different, so there are 12 combinations the two |
329 // two values can exist in four columns: |
329 // values can exist in four columns: |
330 // |
330 // |
331 // (column = X AND column2 = Y) OR |
331 // (column = X AND column2 = Y) OR |
332 // (column = X AND column3 = Y) OR |
332 // (column = X AND column3 = Y) OR |
333 // (column = X AND column4 = Y) OR |
333 // (column = X AND column4 = Y) OR |
334 // (column2 = X AND column3 = Y) OR |
334 // (column2 = X AND column3 = Y) OR |
501 // -> |
501 // -> |
502 // (NOT(NOT(column1) AND NOT(column2) AND NOT(column3) AND NOT(column4)) |
502 // (NOT(NOT(column1) AND NOT(column2) AND NOT(column3) AND NOT(column4)) |
503 // |
503 // |
504 // Which means: |
504 // Which means: |
505 // (NOT(NOT(N>lower && < N<upper) AND NOT(N2>lower && < N2<upper) AND |
505 // (NOT(NOT(N>lower && < N<upper) AND NOT(N2>lower && < N2<upper) AND |
506 // NOT(N3>lower && < N3<upper) AND NOT(N>lower && < N<upper)) |
506 // NOT(N3>lower && < N3<upper) AND NOT(N4>lower && < N4<upper)) |
507 // |
507 // |
508 // As KColumn1 is most likely to contain a match, "NOT(KColumn1)" is more |
508 // As KColumn1 is most likely to contain a match, "NOT(KColumn1)" is more |
509 // likely to be false than "NOT(KColumn2)" etc. So put KColumn1 first in the |
509 // likely to be false than "NOT(KColumn2)" etc. So put KColumn1 first in the |
510 // AND statement. |
510 // AND statement. |
511 return QString("(NOT(NOT(" + |
511 return QString("(NOT(NOT(" + |