Bug Summary

File:libsynthesis/src/sysync/multifielditem.cpp
Warning:line 585, column 8
Called C++ object pointer is null

Annotated Source Code

1/*
2 * File: MultiFieldItem.cpp
3 *
4 * Author: Lukas Zeller (luz@plan44.ch)
5 *
6 * TMultiFieldItem
7 * Item consisting of multiple data fields (TItemField objects)
8 *
9 * Copyright (c) 2001-2011 by Synthesis AG + plan44.ch
10 *
11 * 2001-08-08 : luz : created
12 *
13 */
14
15// includes
16#include "prefix_file.h"
17#include "sysync.h"
18#include "multifielditem.h"
19#include "multifielditemtype.h"
20
21
22using namespace sysync;
23
24namespace sysync {
25
26// Config
27// ======
28
29
30TFieldListConfig::TFieldListConfig(const char* aName, TConfigElement *aParentElement) :
31 TConfigElement(aName,aParentElement)
32{
33 clear();
34} // TFieldListConfig::TFieldListConfig
35
36
37TFieldListConfig::~TFieldListConfig()
38{
39 clear();
40} // TFieldListConfig::~TFieldListConfig
41
42
43// init defaults
44void TFieldListConfig::clear(void)
45{
46 // init defaults
47 fAgeSortable=false;
48 fFields.clear();
49 #ifdef HARDCODED_TYPE_SUPPORT
50 fFieldListTemplateP=NULL__null;
51 #endif
52 // clear inherited
53 inherited::clear();
54} // TFieldListConfig::clear
55
56
57#ifdef CONFIGURABLE_TYPE_SUPPORT1
58
59// config element parsing
60bool TFieldListConfig::localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine)
61{
62 // - fieldlist entry
63 // <field name="REV" type="timestamp" compare="never" age="yes" merge="no"/>
64 if (strucmp(aElementName,"field")==0) {
65 // may not contain anything
66 expectEmpty();
67 // check attributes
68 const char *nam = getAttr(aAttributes,"name");
69 const char *type = getAttr(aAttributes,"type");
70 const char *rel = getAttr(aAttributes,"compare");
71 if (!(nam && *nam && type && rel))
72 return fail("'field' must have 'name', 'type' and 'compare' attributes");
73 // parse enums
74 sInt16 ty;
75 if (!StrToEnum(ItemFieldTypeNames,numFieldTypes,ty,type))
76 return fail("Unknown 'type' attribute: '%s'",type);
77 sInt16 eqrel;
78 if (!StrToEnum(compareRelevanceNames,numEQmodes,eqrel,rel))
79 return fail("Unknown 'compare' attribute: '%s'",rel);
80 // set defaults
81 bool agerelevant=false; // not age relevant by default
82 sInt16 mergemode=mem_none-1; // no merge by default
83 // get optional attributes
84 if (!getAttrBool(aAttributes,"age",agerelevant,true))
85 return fail("Bad boolean value");
86 #ifdef ARRAYFIELD_SUPPORT1
87 bool array=false; // not an array
88 if (!getAttrBool(aAttributes,"array",array,true))
89 return fail("Bad boolean value");
90 #endif
91 const char *p = getAttr(aAttributes,"merge");
92 if (p) {
93 // sort out special cases
94 if (strucmp(p,"no")==0)
95 mergemode=mem_none-1;
96 else if (strucmp(p,"fillempty")==0)
97 mergemode=mem_fillempty-2;
98 else if (strucmp(p,"addunassigned")==0)
99 mergemode=mem_addunassigned-3;
100 else if (strucmp(p,"append")==0)
101 mergemode=mem_concat0;
102 else if (strucmp(p,"lines")==0)
103 mergemode='\n';
104 else if (strlen(p)==1)
105 mergemode=*p; // single char is merge char
106 else
107 return fail("Invalid value '%s' for 'merge' attribute",p);
108 }
109 // now add new field specification
110 TFieldDefinition fielddef;
111 // prepare template element
112 fielddef.type=(TItemFieldTypes)ty;
113 #ifdef ARRAYFIELD_SUPPORT1
114 fielddef.array = array;
115 #endif
116 TCFG_ASSIGN(fielddef.fieldname,nam){ if (nam) fielddef.fieldname=nam; else fielddef.fieldname.erase
(); }
;
117 fielddef.eqRelevant=(TEqualityMode)eqrel;
118 fielddef.ageRelevant=agerelevant;
119 fAgeSortable=fAgeSortable || fielddef.ageRelevant; // if at least one field is age-relevant, we can sort items
120 fielddef.mergeMode=mergemode;
121 // copy into array
122 fFields.push_back(fielddef);
123 }
124 // - none known here
125 else
126 return inherited::localStartElement(aElementName,aAttributes,aLine);
127 // ok
128 return true;
129} // TFieldListConfig::localStartElement
130
131
132// resolve
133void TFieldListConfig::localResolve(bool aLastPass)
134{
135 if (aLastPass) {
136 // check for required settings
137 if (fFields.size()==0)
138 SYSYNC_THROW(TSyncException("fieldlist must contain at least one field"))throw TSyncException("fieldlist must contain at least one field"
)
;
139 }
140 // resolve inherited
141 inherited::localResolve(aLastPass);
142} // TFieldListConfig::localResolve
143
144#endif
145
146
147// get index of a field
148sInt16 TFieldListConfig::fieldIndex(const char *aName, size_t aLen)
149{
150 TFieldDefinitionList::iterator pos;
151 sInt16 n;
152 for (n=0,pos=fFields.begin(); pos!=fFields.end(); ++n,pos++) {
153 if (strucmp(aName,pos->TCFG_CSTR(fieldname)fieldname.c_str(),aLen)==0) {
154 return n; // return field ID
155 }
156 }
157 return VARIDX_UNDEFINED-128; // not found
158} // TFieldListConfig::fieldIndex
159
160
161// profile handler
162
163TProfileHandler::TProfileHandler(TProfileConfig *aProfileCfgP, TMultiFieldItemType *aItemTypeP)
164{
165 // save profile config pointer
166 fItemTypeP = aItemTypeP;
167 // no related datastore yet
168 fRelatedDatastoreP = NULL__null;
169} // TProfileHandler::TProfileHandler
170
171
172TProfileHandler::~TProfileHandler()
173{
174 // nop for now
175} // TProfileHandler::~TProfileHandler
176
177
178// - get session pointer
179TSyncSession *TProfileHandler::getSession(void)
180{
181 return fItemTypeP ? fItemTypeP->getSession() : NULL__null;
182} // TProfileHandler::getSession
183
184// - get session zones pointer
185GZones *TProfileHandler::getSessionZones(void)
186{
187 return fItemTypeP ? fItemTypeP->getSessionZones() : NULL__null;
188} // TProfileHandler::getSessionZones
189
190
191#ifdef SYDEBUG2
192
193TDebugLogger *TProfileHandler::getDbgLogger(void)
194{
195 // commands log to session's logger
196 return fItemTypeP ? fItemTypeP->getDbgLogger() : NULL__null;
197} // TProfileHandler::getDbgLogger
198
199uInt32 TProfileHandler::getDbgMask(void)
200{
201 if (!fItemTypeP) return 0; // no item type, no debug
202 return fItemTypeP->getDbgMask();
203} // TProfileHandler::getDbgMask
204
205#endif
206
207
208// - check availability (depends on item "supported" flags only in SyncML datastore context)
209bool TProfileHandler::isFieldAvailable(TMultiFieldItem &aItem, sInt16 aFieldIndex)
210{
211 if (fRelatedDatastoreP) {
212 // in datastore/SyncML context, only fields supported on both sides are considered "available"
213 return aItem.isAvailable(aFieldIndex);
214 }
215 else {
216 // in non-datastore context, all fields are considered available, as long as
217 // the field index is in range
218 TMultiFieldItemType *mfitP = aItem.getItemType();
219 return mfitP && mfitP->isFieldIndexValid(aFieldIndex);
220 }
221} // TProfileHandler::isFieldAvailable
222
223
224
225
226
227
228// Profile config root element
229
230TProfileConfig::TProfileConfig(const char* aName, TConfigElement *aParentElement) :
231 TConfigElement(aName,aParentElement)
232{
233 clear();
234} // TProfileConfig::TProfileConfig
235
236
237TProfileConfig::~TProfileConfig()
238{
239 clear();
240} // TProfileConfig::~TProfileConfig
241
242
243// init defaults
244void TProfileConfig::clear(void)
245{
246 // init defaults
247 fFieldListP=NULL__null; // no field list linked
248 // clear inherited
249 inherited::clear();
250} // TProfileConfig::clear
251
252
253
254#ifdef HARDCODED_TYPE_SUPPORT
255
256// read hardcoded fieldlist config
257void TFieldListConfig::readFieldListTemplate(const TFieldDefinitionsTemplate *aTemplateP)
258{
259 if (!aTemplateP) return;
260 // save the link to the template as well (we'll need it for maxsize etc. later)
261 fFieldListTemplateP=aTemplateP;
262 fFields.clear();
263 // copy values
264 fAgeSortable=false;
265 TFieldDefinition fielddef;
266 for (sInt16 i=0; i<aTemplateP->numFields; i++) {
267 const TFieldDefinitionTemplate *afieldP= &(aTemplateP->fieldDefs[i]);
268 // prepare template element
269 fielddef.type=afieldP->type;
270 #ifdef ARRAYFIELD_SUPPORT1
271 fielddef.array = afieldP->array;
272 #endif
273 TCFG_ASSIGN(fielddef.fieldname,afieldP->fieldname){ if (afieldP->fieldname) fielddef.fieldname=afieldP->fieldname
; else fielddef.fieldname.erase(); }
;
274 fielddef.eqRelevant=afieldP->eqRelevant;
275 fielddef.ageRelevant=afieldP->ageRelevant;
276 fAgeSortable=fAgeSortable || fielddef.ageRelevant; // if at least one field is age-relevant, we can sort
277 fielddef.mergeMode=afieldP->mergeMode;
278 // copy into array
279 fFields.push_back(fielddef);
280 }
281} // TFieldListConfig::readFieldListTemplate
282
283#endif
284
285
286
287TMultiFieldDatatypesConfig::TMultiFieldDatatypesConfig(TConfigElement *aParentElement) :
288 TDatatypesConfig("datatypes",aParentElement)
289{
290 clear();
291} // TMultiFieldDatatypesConfig::TMultiFieldDatatypesConfig
292
293
294TMultiFieldDatatypesConfig::~TMultiFieldDatatypesConfig()
295{
296 // make sure we don't re-build types (createHardcodedTypes() in clear())
297 // so we call internalClear() here!
298 internalClear();
299} // TMultiFieldDatatypesConfig::~TMultiFieldDatatypesConfig
300
301
302// init defaults
303void TMultiFieldDatatypesConfig::clear(void)
304{
305 // remove internals
306 internalClear();
307 // Now datatypes registry is really empty
308 #ifdef HARDCODED_TYPE_SUPPORT
309 // - add hard-coded default type information (if any)
310 static_cast<TRootConfig *>(getRootElement())->createHardcodedTypes(this);
311 #endif
312} // TMultiFieldDatatypesConfig::clear
313
314
315// init defaults
316void TMultiFieldDatatypesConfig::internalClear(void)
317{
318 // remove fieldlists
319 TFieldListsList::iterator pos1;
320 for(pos1=fFieldLists.begin();pos1!=fFieldLists.end();pos1++)
321 delete *pos1;
322 fFieldLists.clear();
323 // remove profiles
324 TProfilesList::iterator pos2;
325 for(pos2=fProfiles.begin();pos2!=fProfiles.end();pos2++)
326 delete *pos2;
327 fProfiles.clear();
328 // clear inherited
329 inherited::clear();
330} // TMultiFieldDatatypesConfig::internalClear
331
332
333// get a field list by name
334TFieldListConfig *TMultiFieldDatatypesConfig::getFieldList(const char *aName)
335{
336 TFieldListsList::iterator pos;
337 for(pos=fFieldLists.begin();pos!=fFieldLists.end();pos++) {
338 if (strucmp((*pos)->getName(),aName)==0) {
339 // found
340 return *pos;
341 }
342 }
343 return NULL__null; // not found
344} // TMultiFieldDatatypesConfig::getFieldList
345
346
347// get a profile by name
348TProfileConfig *TMultiFieldDatatypesConfig::getProfile(const char *aName)
349{
350 TProfilesList::iterator pos;
351 for(pos=fProfiles.begin();pos!=fProfiles.end();pos++) {
352 if (strucmp((*pos)->getName(),aName)==0) {
353 // found
354 return *pos;
355 }
356 }
357 return NULL__null; // not found
358} // TMultiFieldDatatypesConfig::getProfile
359
360
361
362#ifdef CONFIGURABLE_TYPE_SUPPORT1
363
364// config element parsing
365bool TMultiFieldDatatypesConfig::localStartElement(const char *aElementName, const char **aAttributes, sInt32 aLine)
366{
367 // checking the elements
368 // - field lists or profiles can appear at this level
369 bool newFieldList=false;
370 TProfileConfig *newProfileP=NULL__null;
371 TFieldListConfig *flP = NULL__null;
372 // in case it is a field list or a profile - check for name
373 const char* nam = getAttr(aAttributes,"name");
374 // now check if fieldlist or profile
375 if (strucmp(aElementName,"fieldlist")==0) {
376 newFieldList=true;
377 }
378 // the xml tag itself is used as the profile's typename (historical reasons/compatibility with existing config)
379 else if ((newProfileP=getSyncAppBase()->getRootConfig()->newProfileConfig(nam,aElementName,this))!=NULL__null) {
380 const char* flnam = getAttr(aAttributes,"fieldlist");
381 if (!flnam)
382 return fail("%s is missing 'fieldlist' attribute",aElementName);
383 else {
384 flP = getFieldList(flnam);
385 if (!flP)
386 return fail("fieldlist '%s' unknown in %s",flnam,aElementName);
387 }
388 }
389 // - tag not known here
390 else
391 return TDatatypesConfig::localStartElement(aElementName,aAttributes,aLine);
392 // known tag, check if we need further processing
393 if (newFieldList || newProfileP) {
394 if (!nam)
395 return fail("%s is missing 'name' attribute",aElementName);
396 // create new named field list or use already created profile
397 if (newFieldList) {
398 // new field list
399 TFieldListConfig *fieldlistcfgP = new TFieldListConfig(nam,this);
400 fFieldLists.push_back(fieldlistcfgP); // save in list
401 expectChildParsing(*fieldlistcfgP); // let element handle parsing
402 }
403 else {
404 // new profile
405 newProfileP->fFieldListP=flP; // set field list for profile
406 fProfiles.push_back(newProfileP); // save in list
407 expectChildParsing(*newProfileP); // let element handle parsing
408 }
409 }
410 // ok
411 return true;
412} // TMultiFieldDatatypesConfig::localStartElement
413
414
415// resolve
416void TMultiFieldDatatypesConfig::localResolve(bool aLastPass)
417{
418 // resolve profiles
419 TProfilesList::iterator pos1;
420 for(pos1=fProfiles.begin();pos1!=fProfiles.end();pos1++) {
421 (*pos1)->localResolve(aLastPass);
422 }
423 // resolve field lists
424 TFieldListsList::iterator pos2;
425 for(pos2=fFieldLists.begin();pos2!=fFieldLists.end();pos2++) {
426 (*pos2)->localResolve(aLastPass);
427 }
428 // resolve inherited
429 inherited::localResolve(aLastPass);
430} // TMultiFieldDatatypesConfig::localResolve
431
432
433#endif
434
435
436/*
437 * Implementation of TMultiFieldItem
438 */
439
440/* public TMultiFieldItem members */
441
442
443TMultiFieldItem::TMultiFieldItem(
444 TMultiFieldItemType *aItemTypeP, // owner's (=source) type
445 TMultiFieldItemType *aTargetItemTypeP // target type (for optimization)
446) :
447 TSyncItem(aItemTypeP)
448{
449 // save types
450 fItemTypeP = aItemTypeP; // owner (source) type
451 fTargetItemTypeP = aTargetItemTypeP; // target (destination) type
452 // copy field definitions pointer for fast access
453 fFieldDefinitionsP = fItemTypeP->getFieldDefinitions();
454 if (!fFieldDefinitionsP)
455 SYSYNC_THROW(TSyncException(DEBUGTEXT("MultiFieldItem without FieldDefinitions","mfi3")))throw TSyncException("MultiFieldItem without FieldDefinitions"
)
;
456 // test if target has same field defs
457 if (fTargetItemTypeP->getFieldDefinitions()!=fFieldDefinitionsP)
458 SYSYNC_THROW(TSyncException(DEBUGTEXT("MultiFieldItem with non-matching target field definitions","mfi1")))throw TSyncException("MultiFieldItem with non-matching target field definitions"
)
;
459 // create fields array
460 fFieldsP = new TItemFieldP[fFieldDefinitionsP->numFields()];
461 // - init it with null pointers
462 for (sInt16 i=0; i<fFieldDefinitionsP->numFields(); i++) fFieldsP[i]=NULL__null;
463} // TMultiFieldItem::TMultiFieldItem
464
465
466TMultiFieldItem::~TMultiFieldItem()
467{
468 // remove fields
469 cleardata();
470 // remove fields list
471 delete[] fFieldsP;
472} // TMultiFieldItem::~TMultiFieldItem
473
474
475
476// remove all data from item
477void TMultiFieldItem::cleardata(void)
478{
479 if (fFieldDefinitionsP) {
480 for (sInt16 i=0; i<fFieldDefinitionsP->numFields(); i++) {
481 if (fFieldsP[i]) {
482 delete fFieldsP[i]; // delete field object
483 fFieldsP[i]=NULL__null;
484 }
485 }
486 }
487} // TMultiFieldItem::cleardata
488
489
490#if defined(CHECKSUM_CHANGELOG1) && !defined(RECORDHASH_FROM_DBAPI)
491
492// changelog support: calculate CRC over contents
493uInt16 TMultiFieldItem::getDataCRC(uInt16 crc, bool aEQRelevantOnly)
494{
495 // iterate over all fields
496 if (fFieldDefinitionsP) {
497 for (sInt16 i=0; i<fFieldDefinitionsP->numFields(); i++) {
498 if (!aEQRelevantOnly || fFieldDefinitionsP->fFields[i].eqRelevant!=eqm_none) {
499 if (fFieldsP[i]) {
500 crc=fFieldsP[i]->getDataCRC(crc);
501 }
502 }
503 }
504 }
505 return crc;
506} // TMultiFieldItem::getDataCRC
507
508#endif
509
510
511
512// adjust fid and repeat offset to access array element if
513// base fid is an array field or to offset fid accordingly
514// if based fid is NOT an array field
515// - returns adjusted aFid and aIndex ready to be used with getArrayField()
516// - returns true if aFid IS an array field
517bool TMultiFieldItem::adjustFidAndIndex(sInt16 &aFid, sInt16 &aIndex)
518{
519 bool arrfield;
520
521 #ifdef ARRAYFIELD_SUPPORT1
522 // fid is offset repoffset only if not an array field
523 arrfield=true;
524 // check for array field first
525 TItemField *fldP = getField(aFid);
526 if (fldP) {
527 if (!(fldP->isArray())) {
528 // no array field
529 arrfield=false;
530 aFid += aIndex; // use array offset as additional field ID offset
531 aIndex=0; // no array index
532 }
533 }
534 else {
535 // Note: if field does not exist, do not apply offset, but don't report array field either!
536 arrfield = false;
537 }
538 #else
539 // without array support, fid is always offset by rep offset
540 aFid += aIndex;
541 aIndex=0; // no array index
542 arrfield=false;
543 #endif
544 // return true if this is really an array field
545 return arrfield;
546} // adjustFidAndIndex
547
548
549
550// return specified leaf field of array field or regular field
551// depending if aFid addresses an array or not.
552// (This is a shortcut method to access fields specified by a base fid and a repeat)
553TItemField *TMultiFieldItem::getArrayFieldAdjusted(sInt16 aFid, sInt16 aIndex, bool aExistingOnly)
554{
555 adjustFidAndIndex(aFid,aIndex);
556 return getArrayField(aFid, aIndex, aExistingOnly);
557} // TMultiFieldItem::getArrayFieldAdjusted
558
559
560// return specified leaf field of array field
561TItemField *TMultiFieldItem::getArrayField(sInt16 aFid, sInt16 aIndex, bool aExistingOnly)
562{
563 #ifdef ARRAYFIELD_SUPPORT1
564 TItemField *fiP = getField(aFid);
565 if (!fiP) return NULL__null;
566 return fiP->getArrayField(aIndex,aExistingOnly);
567 #else
568 // without array support, we can only access index==0
569 if (aIndex>0) return NULL__null; // other indices don't exist
570 return getField(aFid);
571 #endif
572} // TMultiFieldItem::getArrayField
573
574
575// get field by name (returns NULL if not known, creates if known but not existing yet)
576TItemField *TMultiFieldItem::getArrayField(const char *aFieldName, sInt16 aIndex, bool aExistingOnly)
577{
578 return getArrayField(fItemTypeP->getFieldIndex(aFieldName),aIndex,aExistingOnly);
579} // TMultiFieldItem::getArrayField
580
581
582// get field by index (returns NULL if not known, creates if known but not existing yet)
583TItemField *TMultiFieldItem::getField(sInt16 aFieldIndex)
584{
585 if (!fItemTypeP->isFieldIndexValid(aFieldIndex)) return NULL__null; // invalid index
18
Called C++ object pointer is null
586 TItemField *fiP = fFieldsP[aFieldIndex];
587 if (!fiP) {
588 // we must create the field first
589 fiP=newItemField(
590 fFieldDefinitionsP->fFields[aFieldIndex].type,
591 getSessionZones()
592 #ifdef ARRAYFIELD_SUPPORT1
593 ,fFieldDefinitionsP->fFields[aFieldIndex].array
594 #endif
595 );
596 // save in array
597 fFieldsP[aFieldIndex] = fiP;
598 }
599 return fiP;
600} // TMultiFieldItem::getField
601
602
603// find index of field (returns FID_NOT_SUPPORTED if field is not a field of this item)
604sInt16 TMultiFieldItem::getIndexOfField(const TItemField *aFieldP)
605{
606 for (sInt16 i=0; i<fFieldDefinitionsP->numFields(); i++) {
607 if (fFieldsP[i]==aFieldP) {
608 // found field, return it's index
609 return i;
610 }
611 }
612 return FID_NOT_SUPPORTED-128; // not found
613} // TMultiFieldItem::getIndexOfField
614
615
616
617// get field by name (returns NULL if not known, creates if known but not existing yet)
618TItemField *TMultiFieldItem::getField(const char *aFieldName)
619{
620 return getField(fItemTypeP->getFieldIndex(aFieldName));
621} // TMultiFieldItem::getField
622
623
624// get field reference (create if not yet created)
625// throws if bad index
626TItemField &TMultiFieldItem::getFieldRef(sInt16 aFieldIndex)
627{
628 TItemField *fiP = getField(aFieldIndex);
629 if (!fiP)
630 SYSYNC_THROW(TSyncException(DEBUGTEXT("getFieldRef with bad index called","mfi2")))throw TSyncException("getFieldRef with bad index called"); // invalid index
631 return *fiP;
632} // TMultiFieldItem::getFieldRef
633
634
635// check if field is assigned (exists and has a value)
636bool const TMultiFieldItem::isAssigned(const char *aFieldName)
637{
638 return isAssigned(fItemTypeP->getFieldIndex(aFieldName));
639} // TMultiFieldItem::isAssigned
640
641
642TMultiFieldItemType *TMultiFieldItem::getLocalItemType(void)
643{
644 return fItemTypeP && fItemTypeP->isRemoteType() ? fTargetItemTypeP : fItemTypeP;
645} // TMultiFieldItem::getLocalItemType
646
647
648TMultiFieldItemType *TMultiFieldItem::getRemoteItemType(void)
649{
650 return fItemTypeP && fItemTypeP->isRemoteType() ? fItemTypeP : fTargetItemTypeP;
651} // TMultiFieldItem::getRemoteItemType
652
653
654
655// check if field is assigned (exists and has a value)
656bool const TMultiFieldItem::isAssigned(sInt16 aFieldIndex)
657{
658 // check if field object exists at all
659 if (!fItemTypeP->isFieldIndexValid(aFieldIndex)) return false; // invalid index
660 TItemField *fiP = fFieldsP[aFieldIndex];
661 if (!fiP) return false; // field object does not exist
662 // return if field object is assigned
663 return fiP->isAssigned();
664} // TMultiFieldItem::isAssigned
665
666
667// field availability (combined source & target)
668bool TMultiFieldItem::isAvailable(const char *aFieldName)
669{
670 return isAvailable(fItemTypeP->getFieldIndex(aFieldName));
671} // TMultiFieldItem::isAvailable
672
673
674// field availability (combined source & target)
675bool TMultiFieldItem::isAvailable(sInt16 aFieldIndex)
676{
677 if (fItemTypeP && fTargetItemTypeP) {
678 if (!fItemTypeP->isFieldIndexValid(aFieldIndex)) return false; // invalid index
679 return
680 fItemTypeP->getFieldOptions(aFieldIndex)->available &&
681 fTargetItemTypeP->getFieldOptions(aFieldIndex)->available;
682 }
683 else
684 return false; // source or target missing, not available
685} // TMultiFieldItem::isAvailable
686
687
688bool TMultiFieldItem::knowsRemoteFieldOptions(void)
689{
690 // knows them if either myself or the other side has received devInf
691 // (depends: received item has it in its own type, to be sent one in the target type)
692 return
693 (fItemTypeP && fItemTypeP->hasReceivedFieldOptions()) ||
694 (fTargetItemTypeP && fTargetItemTypeP->hasReceivedFieldOptions());
695} // TMultiFieldItem::knowsRemoteFieldOptions
696
697
698
699// make sure that all fields that are available in source and target are
700// assigned at least an empty value
701void TMultiFieldItem::assignAvailables(void)
702{
703 if (fFieldDefinitionsP) {
704 for (sInt16 k=0; k<fFieldDefinitionsP->numFields(); k++) {
705 if (isAvailable(k)) {
706 TItemField *fldP=getField(k); // force creation
707 if (fldP) {
708 // make sure it is assigned a "empty" value
709 if (fldP->isUnassigned())
710 fldP->assignEmpty();
711 }
712 }
713 }
714 }
715} // TMultiFieldItem::assignAvailables
716
717
718
719
720// cast pointer to same type, returns NULL if incompatible
721TMultiFieldItem *TMultiFieldItem::castToSameTypeP(TSyncItem *aItemP)
722{
723 if (aItemP->isBasedOn(ity_multifield)) {
724 TMultiFieldItem *multifielditemP=static_cast<TMultiFieldItem *> (aItemP);
725 // class compatible, now test type compatibility
726 // - field definition list must be the same instance(!) in both items
727 if (fFieldDefinitionsP==multifielditemP->fFieldDefinitionsP)
728 return multifielditemP;
729 else
730 return NULL__null;
731 }
732 // not even class compatible
733 return NULL__null;
734} // TMultiFieldItem::castToSameTypeP
735
736
737// test if comparable (at least for equality)
738bool TMultiFieldItem::comparable(TSyncItem &aItem)
739{
740 // test if comparable: other type must be same type of multifield
741 return castToSameTypeP(&aItem)!=NULL__null;
742} // TMultiFieldItem::comparable
743
744
745// test if sortable (by age, newer are > than older)
746bool TMultiFieldItem::sortable(TSyncItem &aItem)
747{
748 if (!fFieldDefinitionsP->fAgeSortable) return false; // not sortable at all
749 if (comparable(aItem)) {
750 // item is comparable (has same FieldDefinitions)
751 // Now check if all ageRelevant fields are assigned on both sides
752 // Note: we can static-cast here because comparable() has verified aItem's type
753 TMultiFieldItem *multifielditemP=static_cast<TMultiFieldItem *> (&aItem);
754 // search for ageRelevant fields
755 for (sInt16 i=0; i<fFieldDefinitionsP->numFields(); i++) {
756 if (fFieldDefinitionsP->fFields[i].ageRelevant) {
757 // check if available for both types
758 if (!(
759 isAssigned(i) && // my own
760 multifielditemP->isAssigned(i) // aItem's
761 ))
762 return false; // missing needed field on one side
763 }
764 }
765 return true; // all ageRelevant fields are assigned in both sides
766 }
767 else return false; // not comparable is not sortable either
768} // TMultiFieldItem::sortable
769
770
771#ifdef OBJECT_FILTERING1
772
773
774// check post-fetch filter
775bool TMultiFieldItem::postFetchFiltering(TLocalEngineDS *aDatastoreP)
776{
777 return fItemTypeP->postFetchFiltering(this,aDatastoreP);
778} // TMultiFieldItem::postFetchFiltering
779
780
781// test if item passes filter
782bool TMultiFieldItem::testFilter(const char *aFilterString)
783{
784 // process filter without modifying
785 #ifdef SYDEBUG2
786 PDEBUGPRINTFX(DBG_DATA+DBG_FILTER+DBG_HOT,({ if (((0x00000080 +0x08000000 +0x00000001) & getDbgMask(
)) == (0x00000080 +0x08000000 +0x00000001)) getDbgLogger()->
setNextMask(0x00000080 +0x08000000 +0x00000001).DebugPrintfLastMask
( "Testing filter '%s' against item:", aFilterString ); }
787 "Testing filter '%s' against item:",{ if (((0x00000080 +0x08000000 +0x00000001) & getDbgMask(
)) == (0x00000080 +0x08000000 +0x00000001)) getDbgLogger()->
setNextMask(0x00000080 +0x08000000 +0x00000001).DebugPrintfLastMask
( "Testing filter '%s' against item:", aFilterString ); }
788 aFilterString{ if (((0x00000080 +0x08000000 +0x00000001) & getDbgMask(
)) == (0x00000080 +0x08000000 +0x00000001)) getDbgLogger()->
setNextMask(0x00000080 +0x08000000 +0x00000001).DebugPrintfLastMask
( "Testing filter '%s' against item:", aFilterString ); }
789 )){ if (((0x00000080 +0x08000000 +0x00000001) & getDbgMask(
)) == (0x00000080 +0x08000000 +0x00000001)) getDbgLogger()->
setNextMask(0x00000080 +0x08000000 +0x00000001).DebugPrintfLastMask
( "Testing filter '%s' against item:", aFilterString ); }
;
790 if (*aFilterString && PDEBUGTEST(DBG_DATA+DBG_FILTER+DBG_USERDATA)(((0x00000080 +0x08000000 +0x01000000) & getDbgMask()) ==
(0x00000080 +0x08000000 +0x01000000))
) {
791 debugShowItem(DBG_DATA0x00000080+DBG_FILTER0x08000000);
792 }
793 #endif
794 bool result=processFilter(false,aFilterString);
795 PDEBUGPRINTFX(DBG_DATA+DBG_FILTER+DBG_HOT,({ if (((0x00000080 +0x08000000 +0x00000001) & getDbgMask(
)) == (0x00000080 +0x08000000 +0x00000001)) getDbgLogger()->
setNextMask(0x00000080 +0x08000000 +0x00000001).DebugPrintfLastMask
( "Filter test result is %s", result ? "TRUE" : "FALSE" ); }
796 "Filter test result is %s",{ if (((0x00000080 +0x08000000 +0x00000001) & getDbgMask(
)) == (0x00000080 +0x08000000 +0x00000001)) getDbgLogger()->
setNextMask(0x00000080 +0x08000000 +0x00000001).DebugPrintfLastMask
( "Filter test result is %s", result ? "TRUE" : "FALSE" ); }
797 result ? "TRUE" : "FALSE"{ if (((0x00000080 +0x08000000 +0x00000001) & getDbgMask(
)) == (0x00000080 +0x08000000 +0x00000001)) getDbgLogger()->
setNextMask(0x00000080 +0x08000000 +0x00000001).DebugPrintfLastMask
( "Filter test result is %s", result ? "TRUE" : "FALSE" ); }
798 )){ if (((0x00000080 +0x08000000 +0x00000001) & getDbgMask(
)) == (0x00000080 +0x08000000 +0x00000001)) getDbgLogger()->
setNextMask(0x00000080 +0x08000000 +0x00000001).DebugPrintfLastMask
( "Filter test result is %s", result ? "TRUE" : "FALSE" ); }
;
799 // false on syntax error
800 if (*aFilterString) {
801 PDEBUGPRINTFX(DBG_ERROR,("unexpected chars in filter expression: %s",aFilterString)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("unexpected chars in filter expression: %s"
,aFilterString); }
;
802 return false;
803 }
804 return result;
805} // TMultiFieldItem::testFilter
806
807
808// make item pass filter
809bool TMultiFieldItem::makePassFilter(const char *aFilterString)
810{
811 // process filter with making modifications such that item passes filter condition
812 bool result = processFilter(true,aFilterString);
813 // false on syntax error
814 if (*aFilterString) {
815 PDEBUGPRINTFX(DBG_ERROR+DBG_FILTER,("unexpected chars in filter expression: %s",aFilterString)){ if (((0x00000002 +0x08000000) & getDbgMask()) == (0x00000002
+0x08000000)) getDbgLogger()->setNextMask(0x00000002 +0x08000000
).DebugPrintfLastMask ("unexpected chars in filter expression: %s"
,aFilterString); }
;
816 return false;
817 }
818 return result;
819} // TMultiFieldItem::makePassFilter
820
821
822// process filter expression
823bool TMultiFieldItem::processFilter(bool aMakePass, const char *&aPos, const char *aStop, sInt16 aLastOpPrec)
824{
825 char c=0;
826 const char *st;
827 string str;
828 bool result;
829 sInt16 fid;
830 sInt16 cmpres=0;
831 bool neg;
832 bool assignToMakeTrue;
833 bool specialValue;
834 bool caseinsensitive;
835 TStringField idfield;
836 TItemField *fldP;
837
838 // determine max length
839 if (aStop==NULL__null) aStop=aPos+strlen(aPos);
1
Assuming 'aStop' is not equal to NULL
2
Taking false branch
840 // empty expression is true
841 result=true;
842 // process simple term (<ident><op><value>)
843 // Note: do not allow negation to make sure
844 // that TRUE of a comparison always
845 // adds to TRUE of the entire expression
846 neg=false; // not negated
847 // - get first non-space
848 while (aPos<=aStop) {
3
Assuming 'aPos' is <= 'aStop'
4
Loop condition is true. Entering loop body
7
Loop condition is false. Execution continues on line 855
849 c=*aPos;
850 if (c!=' ') break;
5
Assuming the condition is false
6
Taking false branch
851 aPos++;
852 }
853 // Term starts here, first char is c, aPos points to it
854 // - check subexpression paranthesis
855 if (c=='(') {
8
Taking false branch
856 // boolean term is grouped subexpression, don't stop at logical operation
857 aPos++;
858 result=processFilter(aMakePass,aPos,aStop,0); // dont stop at any logical operator
859 // check if matching paranthesis
860 if (*(aPos++)!=')') {
861 PDEBUGPRINTFX(DBG_ERROR+DBG_FILTER,("Filter expression error (missing \")\") at: %s",--aPos)){ if (((0x00000002 +0x08000000) & getDbgMask()) == (0x00000002
+0x08000000)) getDbgLogger()->setNextMask(0x00000002 +0x08000000
).DebugPrintfLastMask ("Filter expression error (missing \")\") at: %s"
,--aPos); }
;
862 //%%% no, don't skip rest, as otherwise caller will not know that filter processing failed!%%% aPos=aStop; // skip rest
863 return false; // always fail
864 }
865 if (neg) result=!result;
866 }
867 else if (c==0) {
9
Taking false branch
868 // empty term, counts as true
869 return result;
870 }
871 else {
872 // must be simple boolean term
873 // - remember start of ident
874 st=aPos;
875 // - search end of ident
876 while (isFilterIdent(c)(isalnum(c) || c=='_' || c=='.')) c=*(++aPos);
10
Loop condition is false. Execution continues on line 878
877 // - c/aPos=char after ident, get ident
878 str.assign(st,aPos-st);
879 // - check for subscript index
880 uInt16 subsIndex=0; // no index (index is 1-based in DS 1.2 filter specs)
881 if (c=='[') {
11
Taking false branch
882 // expect numeric index
883 aPos++; // next
884 aPos+=StrToUShort(aPos,subsIndex);
885 if (*aPos!=']') {
886 PDEBUGPRINTFX(DBG_ERROR+DBG_FILTER,("Filter expression error (missing \"]\") at: %s",--aPos)){ if (((0x00000002 +0x08000000) & getDbgMask()) == (0x00000002
+0x08000000)) getDbgLogger()->setNextMask(0x00000002 +0x08000000
).DebugPrintfLastMask ("Filter expression error (missing \"]\") at: %s"
,--aPos); }
;
887 return false; // syntax error, does not pass
888 }
889 c=*(++aPos); // process next after subscript
890 }
891 // - get field ID for that ident (can be -1 if none found)
892 // - check special idents first
893 if (str=="LUID") {
12
Taking false branch
894 // this is SyncML-TAF Standard
895 // it is also produced by DS 1.2 &LUID; pseudo-identifier
896 if (IS_CLIENT(!getSyncAppBase()->isServer()))
897 idfield.setAsString(getLocalID());
898 else
899 idfield.setAsString(getRemoteID());
900 fldP=&idfield;
901 }
902 else if (str=="LOCALID") {
13
Taking false branch
903 // this is a Synthesis extension
904 idfield.setAsString(getLocalID());
905 fldP=&idfield;
906 }
907 #ifdef SYSYNC_SERVER1
908 else if (IS_SERVER(getSyncAppBase()->isServer()) && str=="GUID") {
909 // this is a Synthesis extension, added for symmetry to LUID
910 idfield.setAsString(getLocalID());
911 fldP=&idfield;
912 }
913 else if (IS_SERVER(getSyncAppBase()->isServer()) && str=="REMOTEID") {
14
Within the expansion of the macro 'IS_SERVER':
a
Value assigned to field 'fItemTypeP'
b
Assuming the condition is false
914 // this is a Synthesis extension
915 idfield.setAsString(getRemoteID());
916 fldP=&idfield;
917 }
918 #endif // SYSYNC_SERVER
919 else {
920 // must be a field
921 if (fItemTypeP)
15
Assuming pointer value is null
16
Taking false branch
922 fid=fItemTypeP->getFilterIdentifierFieldIndex(str.c_str(),subsIndex);
923 else
924 fid=VARIDX_UNDEFINED-128; // none
925 // now get field pointer (or NULL if field not found)
926 fldP = getField(fid);
17
Calling 'TMultiFieldItem::getField'
927 }
928 // - skip spaces
929 while (isspace(c)) c=*(++aPos);
930 // - check for makepass-assignment modifier ":"
931 assignToMakeTrue=c==':';
932 if (assignToMakeTrue) c=*(++aPos);
933 // - check for special-value modifier "*"
934 specialValue=c=='*';
935 if (specialValue) c=*(++aPos);
936 // - check for case-insensitive comparison mode
937 caseinsensitive=c=='^';
938 if (caseinsensitive) c=*(++aPos);
939 // - now find comparison mode
940 // cmpres = expected strcmp-style result:
941 // 0 if equal, 1 if ident > value, -1 if ident < value,
942 aPos++; // consume first char of comparison anyway
943 if (c=='%') { cmpres=2; } // special flag for CONTAINS
944 else if (c=='$') { cmpres=2; neg=!neg; }
945 else if (c=='=') { cmpres=0; } // equal
946 else if (c=='>') {
947 if (*aPos=='=') { aPos++; neg=!neg; cmpres=-1; } // >= is not <
948 else { cmpres=1; } // >
949 }
950 else if (c=='<') {
951 if (*aPos=='>') { aPos++; neg=!neg; cmpres=0; } // <> is not =
952 else if (*aPos=='=') { aPos++; neg=!neg; cmpres=1; } // <= is not >
953 else { cmpres=-1; } // <
954 }
955 // - now read value
956 st=aPos; // should start here
957 // - find end (end of string, closing paranthesis or logical op)
958 while (aPos<aStop && *aPos!='&' && *aPos!='|' && *aPos!=')') aPos++;
959 // - assign st string
960 str.assign(st,aPos-st);
961 // - check field
962 if (!fldP) {
963 // field does not exist -> result of term, negated or not, is always FALSE
964 result=false;
965 }
966 else {
967 if (cmpres==2) {
968 // "contains"
969 // - create a reference field
970 TItemField *valfldP = newItemField(fldP->getElementType(),getSessionZones());
971 // - assign value as string
972 valfldP->setAsString(str.c_str());
973 result = fldP->contains(*valfldP,caseinsensitive);
974 // assign to make pass if enabled
975 if (!result && aMakePass && assignToMakeTrue) {
976 if (fldP->isArray())
977 fldP->append(*valfldP); // just append another element to make it contained
978 else
979 *fldP = *valfldP; // just overwrite value with to-be-contained value
980 result=true; // now passes
981 }
982 delete valfldP; // no longer needed
983 }
984 else {
985 if (specialValue) {
986 if (cmpres!=0)
987 result=false; // can only compare for equal
988 else {
989 if (str=="E") {
990 // empty
991 result = fldP->isEmpty();
992 }
993 else if (str=="N") {
994 // NULL, unassigned
995 result = fldP->isAssigned();
996 }
997 if (neg) result=!result;
998 // make empty or unassigned to pass filter (make non-empty is not possible)
999 if (!result && aMakePass && assignToMakeTrue && !neg) {
1000 if (str=="E") {
1001 fldP->assignEmpty();
1002 }
1003 else if (str=="N") {
1004 fldP->unAssign();
1005 }
1006 result=true; // now passes
1007 }
1008 }
1009 }
1010 else {
1011 // create a reference field
1012 TItemField *valfldP = newItemField(fldP->getElementType(),getSessionZones());
1013 // assign value as string
1014 valfldP->setAsString(str.c_str());
1015 // compare fields, then compare result with what was expected
1016 result = (fldP->compareWith(*valfldP,caseinsensitive) == cmpres);
1017 // negate result if needed
1018 if (neg) result=!result;
1019 // if field not assigned, comparison is always false
1020 if (fldP->isUnassigned()) result=false;
1021 // assign to make pass if enabled
1022 if (!result && aMakePass && assignToMakeTrue) {
1023 (*fldP) = (*valfldP);
1024 result=true; // now passes
1025 }
1026 // now clear again
1027 delete valfldP;
1028 }
1029 }
1030 }
1031 }
1032 // term is now evaluated, show what follows
1033 // - check for boolean op chain, aPos points now to possible logical operator
1034 do {
1035 // - skip spaces
1036 c=*aPos;
1037 while (c==' ') c=*(++aPos);
1038 // - check char at aPos
1039 if (c=='&') {
1040 // AND
1041 if (2<=aLastOpPrec) return result; // evaluation continues in caller (always as long as we don't have higher prec than AND)
1042 // skip op
1043 aPos++;
1044 // next term must be true as well
1045 // - return when encountering AND, OR and end of expression
1046 // - next term must also be modified to make pass
1047 bool termres = processFilter(aMakePass, aPos, aStop, 2);
1048 result = result && termres;
1049 }
1050 else if (c=='|') {
1051 // OR
1052 if (1<=aLastOpPrec) return result; // evaluation continues in caller
1053 // skip op
1054 aPos++;
1055 // next term must be true only if this one is not true
1056 // - return only when encountering AND or
1057 // - if first term is already true, next must never be modifed to pass
1058 bool termres = processFilter(result ? false : aMakePass, aPos, aStop, 1);
1059 result = result || termres;
1060 }
1061 else {
1062 // End of Expression
1063 // would be: if (0<=aLastOpPrec)
1064 return result;
1065 }
1066 } while(true);
1067}
1068
1069#endif
1070
1071#ifdef SYSYNC_SERVER1
1072
1073// compare function, returns 0 if equal, 1 if this > aItem, -1 if this < aItem
1074sInt16 TMultiFieldItem::compareWith(
1075 TSyncItem &aItem,
1076 TEqualityMode aEqMode,
1077 TLocalEngineDS *aDatastoreP
1078 #ifdef SYDEBUG2
1079 ,bool aDebugShow
1080 #endif
1081)
1082{
1083 #ifndef SYDEBUG2
1084 const aDebugShow = false;
1085 #endif
1086 sInt16 cmpres;
1087 TMultiFieldItem *multifielditemP = castToSameTypeP(&aItem);
1088 if (!multifielditemP) {
1089 cmpres = SYSYNC_NOT_COMPARABLE-999;
1090 goto exit;
1091 }
1092 // do the compare
1093 if (fItemTypeP)
1094 cmpres=fItemTypeP->compareItems(*this,*multifielditemP,aEqMode,aDebugShow,aDatastoreP);
1095 else
1096 cmpres=standardCompareWith(*multifielditemP,aEqMode,aDebugShow);
1097exit:
1098 #ifdef SYDEBUG2
1099 if (aDebugShow) {
1100 OBJDEBUGPRINTFX(getItemType()->getSession(),DBG_DATA,({ if ((getItemType()->getSession()) && (((0x00000080
) & (getItemType()->getSession())->getDbgMask()) ==
(0x00000080))) (getItemType()->getSession())->getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Compared [LOC=%s,REM=%s] with [LOC=%s,REM=%s] (eqMode=%hd), cmpres=%hd"
, getLocalID(), getRemoteID(), aItem.getLocalID(), aItem.getRemoteID
(), (sInt16) aEqMode, cmpres ); }
1101 "Compared [LOC=%s,REM=%s] with [LOC=%s,REM=%s] (eqMode=%hd), cmpres=%hd",{ if ((getItemType()->getSession()) && (((0x00000080
) & (getItemType()->getSession())->getDbgMask()) ==
(0x00000080))) (getItemType()->getSession())->getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Compared [LOC=%s,REM=%s] with [LOC=%s,REM=%s] (eqMode=%hd), cmpres=%hd"
, getLocalID(), getRemoteID(), aItem.getLocalID(), aItem.getRemoteID
(), (sInt16) aEqMode, cmpres ); }
1102 getLocalID(),{ if ((getItemType()->getSession()) && (((0x00000080
) & (getItemType()->getSession())->getDbgMask()) ==
(0x00000080))) (getItemType()->getSession())->getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Compared [LOC=%s,REM=%s] with [LOC=%s,REM=%s] (eqMode=%hd), cmpres=%hd"
, getLocalID(), getRemoteID(), aItem.getLocalID(), aItem.getRemoteID
(), (sInt16) aEqMode, cmpres ); }
1103 getRemoteID(),{ if ((getItemType()->getSession()) && (((0x00000080
) & (getItemType()->getSession())->getDbgMask()) ==
(0x00000080))) (getItemType()->getSession())->getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Compared [LOC=%s,REM=%s] with [LOC=%s,REM=%s] (eqMode=%hd), cmpres=%hd"
, getLocalID(), getRemoteID(), aItem.getLocalID(), aItem.getRemoteID
(), (sInt16) aEqMode, cmpres ); }
1104 aItem.getLocalID(),{ if ((getItemType()->getSession()) && (((0x00000080
) & (getItemType()->getSession())->getDbgMask()) ==
(0x00000080))) (getItemType()->getSession())->getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Compared [LOC=%s,REM=%s] with [LOC=%s,REM=%s] (eqMode=%hd), cmpres=%hd"
, getLocalID(), getRemoteID(), aItem.getLocalID(), aItem.getRemoteID
(), (sInt16) aEqMode, cmpres ); }
1105 aItem.getRemoteID(),{ if ((getItemType()->getSession()) && (((0x00000080
) & (getItemType()->getSession())->getDbgMask()) ==
(0x00000080))) (getItemType()->getSession())->getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Compared [LOC=%s,REM=%s] with [LOC=%s,REM=%s] (eqMode=%hd), cmpres=%hd"
, getLocalID(), getRemoteID(), aItem.getLocalID(), aItem.getRemoteID
(), (sInt16) aEqMode, cmpres ); }
1106 (sInt16) aEqMode,{ if ((getItemType()->getSession()) && (((0x00000080
) & (getItemType()->getSession())->getDbgMask()) ==
(0x00000080))) (getItemType()->getSession())->getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Compared [LOC=%s,REM=%s] with [LOC=%s,REM=%s] (eqMode=%hd), cmpres=%hd"
, getLocalID(), getRemoteID(), aItem.getLocalID(), aItem.getRemoteID
(), (sInt16) aEqMode, cmpres ); }
1107 cmpres{ if ((getItemType()->getSession()) && (((0x00000080
) & (getItemType()->getSession())->getDbgMask()) ==
(0x00000080))) (getItemType()->getSession())->getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Compared [LOC=%s,REM=%s] with [LOC=%s,REM=%s] (eqMode=%hd), cmpres=%hd"
, getLocalID(), getRemoteID(), aItem.getLocalID(), aItem.getRemoteID
(), (sInt16) aEqMode, cmpres ); }
1108 )){ if ((getItemType()->getSession()) && (((0x00000080
) & (getItemType()->getSession())->getDbgMask()) ==
(0x00000080))) (getItemType()->getSession())->getDbgLogger
()->setNextMask(0x00000080).DebugPrintfLastMask ( "Compared [LOC=%s,REM=%s] with [LOC=%s,REM=%s] (eqMode=%hd), cmpres=%hd"
, getLocalID(), getRemoteID(), aItem.getLocalID(), aItem.getRemoteID
(), (sInt16) aEqMode, cmpres ); }
;
1109 }
1110 #endif
1111 return cmpres;
1112} // TMultiFieldItem::compareWith
1113
1114
1115// compare function, returns 0 if equal, 1 if this > aItem, -1 if this < aItem
1116sInt16 TMultiFieldItem::standardCompareWith(
1117 TMultiFieldItem &aItem,
1118 TEqualityMode aEqMode,
1119 bool aDebugShow
1120)
1121{
1122 sInt16 commonfound=0;
1123 sInt16 result=0; // default to equal
1124 // we should test for comparable() before!
1125 if (!comparable(aItem)) {
1126 result=SYSYNC_NOT_COMPARABLE-999;
1127 goto exit;
1128 }
1129 // now compare field-by-field
1130 // - equal means equality of all eqRelevant fields (both non-existing is
1131 // equality, too)
1132 // (but possibly differences in ageRelevant fields)
1133 // - larger/smaller means not equal in eqRelevant fields but
1134 // older/newer by ageRelevant fields
1135 // - SYSYNC_NOT_COMPARABLE means not equal and not ageSortable either
1136 if (aEqMode!=eqm_nocompare) {
1137 for (sInt16 i=0; i<fFieldDefinitionsP->numFields(); i++) {
1138 // both fields must be available in their respective ItemType
1139 if (!getItemType()->getFieldOptions(i)->available ||
1140 !aItem.getItemType()->getFieldOptions(i)->available)
1141 continue; // not available in both items, do not compare
1142 // then test for equality (if relevant in given context)
1143 if (fFieldDefinitionsP->fFields[i].eqRelevant>=aEqMode) {
1144 // at least one is available and relevant in both items
1145 commonfound++;
1146 // this is an EQ-relevant field
1147 // - get fields
1148 TItemField &f1=getFieldRef(i);
1149 TItemField &f2=aItem.getFieldRef(i);
1150 // - For slowsync and firstsync matching, non-ASSIGNED fields will not
1151 // be compared (to allow matching a less-equipped clinet record with its
1152 // better equipped server record and vice versa. Example is the S55
1153 // which discards private addresses, old method rendered lots of
1154 // duplicates on slow sync
1155 if (aEqMode>=eqm_slowsync) {
1156 if (f1.isUnassigned() || f2.isUnassigned())
1157 continue; // omit comparing fields where one side is unassigned
1158 }
1159 // - get assigned status of both fields
1160 // BCPPB revealed bad error: isAssigned was not called (forgot ())!!!
1161 // %%% Note: I think that isAssigned() is the wrong function here, we will use
1162 // !isEmpty(), which returns true for unassigned fields as well as for empty ones
1163 //bool a1 = f1.isAssigned(); // assignment status of field in this item
1164 //bool a2 = f2.isAssigned(); // assignment status of same field in other item
1165 bool a1 = !f1.isEmpty(); // non-empty status of field in this item
1166 bool a2 = !f2.isEmpty(); // non-empty status of same field in other item
1167 // - if both are unassigned -> equal
1168 if (!a1 && !a2) continue; // we are staying equal, test next field
1169 // - if one of them is unassigned -> not equal
1170 // - if both are assigned, fields must be equal
1171 if (!a1 || !a2) {
1172 // one not assigned
1173 result=SYSYNC_NOT_COMPARABLE-999;
1174 #ifdef SYDEBUG2
1175 if (aDebugShow) {
1176 // not assigned
1177 if (!a1) {
1178 PDEBUGPRINTFX(DBG_DATA+DBG_MATCH,("- not equal because fid=%hd not assigned/empty in this item",i)){ if (((0x00000080 +0x10000000) & getDbgMask()) == (0x00000080
+0x10000000)) getDbgLogger()->setNextMask(0x00000080 +0x10000000
).DebugPrintfLastMask ("- not equal because fid=%hd not assigned/empty in this item"
,i); }
;
1179 } else if (!a2) {
1180 PDEBUGPRINTFX(DBG_DATA+DBG_MATCH,("- not equal because fid=%hd not assigned/empty in other item",i)){ if (((0x00000080 +0x10000000) & getDbgMask()) == (0x00000080
+0x10000000)) getDbgLogger()->setNextMask(0x00000080 +0x10000000
).DebugPrintfLastMask ("- not equal because fid=%hd not assigned/empty in other item"
,i); }
;
1181 }
1182 }
1183 #endif
1184 break;
1185 }
1186 else if (f1 != f2) {
1187 // content not equal
1188 #ifdef SYDEBUG2
1189 string ds;
1190 if (aDebugShow) {
1191 // assigned but not equal
1192 PDEBUGPRINTFX(DBG_DATA+DBG_MATCH,("- not equal because fid=%hd not same in both items:",i)){ if (((0x00000080 +0x10000000) & getDbgMask()) == (0x00000080
+0x10000000)) getDbgLogger()->setNextMask(0x00000080 +0x10000000
).DebugPrintfLastMask ("- not equal because fid=%hd not same in both items:"
,i); }
;
1193 getField(i)->getAsString(ds);
1194 PDEBUGPRINTFX(DBG_DATA+DBG_MATCH+DBG_USERDATA,({ if (((0x00000080 +0x10000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x10000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x10000000 +0x01000000).DebugPrintfLastMask
( "- this item : '%-.1000s'",ds.c_str() ); }
1195 "- this item : '%-.1000s'",ds.c_str(){ if (((0x00000080 +0x10000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x10000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x10000000 +0x01000000).DebugPrintfLastMask
( "- this item : '%-.1000s'",ds.c_str() ); }
1196 )){ if (((0x00000080 +0x10000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x10000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x10000000 +0x01000000).DebugPrintfLastMask
( "- this item : '%-.1000s'",ds.c_str() ); }
;
1197 aItem.getField(i)->getAsString(ds);
1198 PDEBUGPRINTFX(DBG_DATA+DBG_MATCH+DBG_USERDATA,({ if (((0x00000080 +0x10000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x10000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x10000000 +0x01000000).DebugPrintfLastMask
( "- other item : '%-.1000s'",ds.c_str() ); }
1199 "- other item : '%-.1000s'",ds.c_str(){ if (((0x00000080 +0x10000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x10000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x10000000 +0x01000000).DebugPrintfLastMask
( "- other item : '%-.1000s'",ds.c_str() ); }
1200 )){ if (((0x00000080 +0x10000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x10000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x10000000 +0x01000000).DebugPrintfLastMask
( "- other item : '%-.1000s'",ds.c_str() ); }
;
1201 PDEBUGPRINTFX(DBG_DATA+DBG_MATCH,({ if (((0x00000080 +0x10000000) & getDbgMask()) == (0x00000080
+0x10000000)) getDbgLogger()->setNextMask(0x00000080 +0x10000000
).DebugPrintfLastMask ( "- thisItem.CompareWith(otherItem) = %hd"
, getFieldRef(i).compareWith(aItem.getFieldRef(i)) ); }
1202 "- thisItem.CompareWith(otherItem) = %hd",{ if (((0x00000080 +0x10000000) & getDbgMask()) == (0x00000080
+0x10000000)) getDbgLogger()->setNextMask(0x00000080 +0x10000000
).DebugPrintfLastMask ( "- thisItem.CompareWith(otherItem) = %hd"
, getFieldRef(i).compareWith(aItem.getFieldRef(i)) ); }
1203 getFieldRef(i).compareWith(aItem.getFieldRef(i)){ if (((0x00000080 +0x10000000) & getDbgMask()) == (0x00000080
+0x10000000)) getDbgLogger()->setNextMask(0x00000080 +0x10000000
).DebugPrintfLastMask ( "- thisItem.CompareWith(otherItem) = %hd"
, getFieldRef(i).compareWith(aItem.getFieldRef(i)) ); }
1204 )){ if (((0x00000080 +0x10000000) & getDbgMask()) == (0x00000080
+0x10000000)) getDbgLogger()->setNextMask(0x00000080 +0x10000000
).DebugPrintfLastMask ( "- thisItem.CompareWith(otherItem) = %hd"
, getFieldRef(i).compareWith(aItem.getFieldRef(i)) ); }
;
1205 }
1206 #endif
1207 // now check for cut-off situation
1208 sInt32 s1=getItemType()->getFieldOptions(i)->maxsize;
1209 sInt32 s2=aItem.getItemType()->getFieldOptions(i)->maxsize;
1210 // Note: (2002-12-01) do not actually use size, as it will probably not be accurate enough,
1211 // but always pass FIELD_OPT_MAXSIZE_UNKNOWN.
1212 if (s1!=FIELD_OPT_MAXSIZE_NONE0) s1=FIELD_OPT_MAXSIZE_UNKNOWN-1;
1213 if (s2!=FIELD_OPT_MAXSIZE_NONE0) s2=FIELD_OPT_MAXSIZE_UNKNOWN-1;
1214 // Now check short versions
1215 if (f1.isShortVers(f2,s2) || f2.isShortVers(f1,s1)) {
1216 // cutoff detected, counts as equal
1217 #ifdef SYDEBUG2
1218 if (aDebugShow) {
1219 PDEBUGPRINTFX(DBG_DATA+DBG_MATCH,({ if (((0x00000080 +0x10000000) & getDbgMask()) == (0x00000080
+0x10000000)) getDbgLogger()->setNextMask(0x00000080 +0x10000000
).DebugPrintfLastMask ( "- Cutoff detected, field considered equal, maxsize(thisitem)=%ld, maxsize(otheritem)=%ld"
, (long)s1,(long)s2 ); }
1220 "- Cutoff detected, field considered equal, maxsize(thisitem)=%ld, maxsize(otheritem)=%ld",{ if (((0x00000080 +0x10000000) & getDbgMask()) == (0x00000080
+0x10000000)) getDbgLogger()->setNextMask(0x00000080 +0x10000000
).DebugPrintfLastMask ( "- Cutoff detected, field considered equal, maxsize(thisitem)=%ld, maxsize(otheritem)=%ld"
, (long)s1,(long)s2 ); }
1221 (long)s1,(long)s2{ if (((0x00000080 +0x10000000) & getDbgMask()) == (0x00000080
+0x10000000)) getDbgLogger()->setNextMask(0x00000080 +0x10000000
).DebugPrintfLastMask ( "- Cutoff detected, field considered equal, maxsize(thisitem)=%ld, maxsize(otheritem)=%ld"
, (long)s1,(long)s2 ); }
1222 )){ if (((0x00000080 +0x10000000) & getDbgMask()) == (0x00000080
+0x10000000)) getDbgLogger()->setNextMask(0x00000080 +0x10000000
).DebugPrintfLastMask ( "- Cutoff detected, field considered equal, maxsize(thisitem)=%ld, maxsize(otheritem)=%ld"
, (long)s1,(long)s2 ); }
;
1223 }
1224 #endif
1225 }
1226 else {
1227 // no cutoff, not equal
1228 result=SYSYNC_NOT_COMPARABLE-999;
1229 break;
1230 }
1231 } // else if not equal
1232 } // if eq-relevant
1233 } // for all fields
1234 } // if EQ-compare at all
1235 if (!commonfound) result=SYSYNC_NOT_COMPARABLE-999;
1236 // if not equal, try to compare age (if age-sortable item at all)
1237 if (result!=0 && fFieldDefinitionsP->fAgeSortable) {
1238 for (sInt16 i=0; i<fFieldDefinitionsP->numFields(); i++) {
1239 // then test for age (if relevant)
1240 if (fFieldDefinitionsP->fFields[i].ageRelevant) {
1241 // this is an age relevant field
1242 // - get assigned status of both fields
1243 bool a1 = isAssigned(i); // assignment status of field in this item
1244 bool a2 = aItem.isAssigned(i); // assignment status of same field in other item
1245 // - if both are unassigned -> cannot decide, continue
1246 if (!a1 && !a2) continue; // test next field
1247 // - if one of them is unassigned -> not age-comparable
1248 if (!a1 || !a2) {
1249 result=SYSYNC_NOT_COMPARABLE-999;
1250 goto exit;
1251 }
1252 // - if both are assigned, return field comparison value
1253 result=getFieldRef(i).compareWith(aItem.getFieldRef(i));
1254 if (result!=0) {
1255 // not equal, newer item determined
1256 goto exit;
1257 }
1258 // continue to resolve age with next fields
1259 }
1260 }
1261 // no age relevant fields or all age relevant fields equal (possibly all unassigned)
1262 result=SYSYNC_NOT_COMPARABLE-999;
1263 }
1264 // done
1265exit:
1266 return result;
1267} // TMultiFieldItem::standardCompareWith
1268
1269#endif // server only
1270
1271
1272
1273// update dependencies of fields (such as BLOB proxies) on localID
1274void TMultiFieldItem::updateLocalIDDependencies(void)
1275{
1276 const char *localid = getLocalID();
1277 // go through all fields
1278 for (sInt16 k=0; k<fFieldDefinitionsP->numFields(); k++) {
1279 TItemField *fldP = getField(k);
1280 for (sInt16 i=0; i<fldP->arraySize(); i++) {
1281 TItemField *leaffldP = fldP->getArrayField(i);
1282 if (leaffldP) leaffldP->setParentLocalID(localid);
1283 }
1284 }
1285} // TMultiFieldItem::updateLocalIDDependencies
1286
1287
1288
1289
1290/// @brief replace data contents from specified item
1291/// @param aAvailableOnly: only replace contents actually available in aItem, leave rest untouched
1292/// NOTE: this was changed slightly between 1.x.8.5 and 1.x.8.6:
1293/// If the source type has not received devinf saying which fields are available,
1294/// only fields that are actually ASSIGNED are written. If aAssignedOnly is
1295/// additionally set, only assigned fields will be written anyway.
1296/// @param aDetectCutOffs: use field's maxsize specs to detect contents cut off by limited field
1297/// lengths and do not replace data if target is equal with source up to field length
1298/// @param aAssignedOnly: just copy assigned fields (no check for availability)
1299/// @param aTransferUnassigned: transfer unassigned status from source item (i.e. unassign those
1300/// in target that are unassigned in source, no check for availability)
1301bool TMultiFieldItem::replaceDataFrom(TSyncItem &aItem, bool aAvailableOnly, bool aDetectCutoffs, bool aAssignedOnly, bool aTransferUnassigned)
1302{
1303 TMultiFieldItem *multifielditemP = castToSameTypeP(&aItem);
1304 if (!multifielditemP) return false;
1305 // ok, same type, copy data
1306 for (sInt16 i=0; i<fFieldDefinitionsP->numFields(); i++) {
1307 if (
1308 !aAvailableOnly || (
1309 !aAssignedOnly && // availability is relevant only if not aAssignedOnly
1310 multifielditemP->fItemTypeP->hasReceivedFieldOptions() &&
1311 multifielditemP->fItemTypeP->getFieldOptions(i)->available
1312 )
1313 || multifielditemP->isAssigned(i)
1314 ) {
1315 // copy field
1316 sInt32 siz=multifielditemP->fItemTypeP->getFieldOptions(i)->maxsize;
1317 if (aDetectCutoffs && siz!=FIELD_OPT_MAXSIZE_NONE0) {
1318 // check if source fields's content is fully contained at beginning of
1319 // target string, if yes, don't do anything
1320 // Note: (2002-12-01) do not actually use size, as it will probably not be accurate enough,
1321 // but always pass FIELD_OPT_MAXSIZE_UNKNOWN.
1322 if (getFieldRef(i).isShortVers(multifielditemP->getFieldRef(i),FIELD_OPT_MAXSIZE_UNKNOWN-1)) {
1323 // yes, we think that this is a cut-off,
1324 // so leave target untouched as it has more complete version of this field
1325 continue;
1326 }
1327 }
1328 // copy source field into this target field
1329 getFieldRef(i)=multifielditemP->getFieldRef(i);
1330 }
1331 else if (aTransferUnassigned && !multifielditemP->isAssigned(i)) {
1332 // explicitly transfer unassigned status
1333 // Note: this is useful in read-modify-write done exclusively for cutoff prevention,
1334 // as it prevents re-writing fields that were not actually transmitted from the remote
1335 // (i.e. no get-from-DB-and-write-same-value-back). Might be essential in case of special
1336 // fields where the datastore MUST know if these were sent with the data, like FN in pocketpc)
1337 getFieldRef(i).unAssign();
1338 }
1339 }
1340 return true;
1341} // TMultiFieldItem::replaceDataFrom
1342
1343
1344// check item before processing it
1345bool TMultiFieldItem::checkItem(TLocalEngineDS *aDatastoreP)
1346{
1347 return fItemTypeP->checkItem(*this,aDatastoreP);
1348} // TMultiFieldItem::checkItem
1349
1350
1351#ifdef SYSYNC_SERVER1
1352
1353// merge this item with specified item.
1354// Notes:
1355// - specified item is treated as loosing item, this item is winning item
1356// - also updates other item to make sure it is equal to the winning after the merge
1357// sets (but does not reset) change status of this and other item.
1358// Note that changes of non-relevant fields are not reported here.
1359void TMultiFieldItem::mergeWith(TSyncItem &aItem, bool &aChangedThis, bool &aChangedOther, TLocalEngineDS *aDatastoreP, int mode)
1360{
1361 TMultiFieldItem *multifielditemP = castToSameTypeP(&aItem);
1362 if (!multifielditemP) return;
1363 // do the merge
1364 if (fItemTypeP)
1365 fItemTypeP->mergeItems(*this,*multifielditemP,aChangedThis,aChangedOther,aDatastoreP, mode);
1366 else
1367 standardMergeWith(*multifielditemP,aChangedThis,aChangedOther, mode);
1368 // show result
1369 OBJDEBUGPRINTFX(getItemType()->getSession(),DBG_DATA+DBG_CONFLICT,({ if ((getItemType()->getSession()) && (((0x00000080
+0x20000000) & (getItemType()->getSession())->getDbgMask
()) == (0x00000080 +0x20000000))) (getItemType()->getSession
())->getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "mergeWith() final status: thisitem: %schanged, otheritem: %schanged (relevant; eqm_none field changes are not indicated)"
, aChangedThis ? "" : "not ", aChangedOther ? "" : "not " ); }
1370 "mergeWith() final status: thisitem: %schanged, otheritem: %schanged (relevant; eqm_none field changes are not indicated)",{ if ((getItemType()->getSession()) && (((0x00000080
+0x20000000) & (getItemType()->getSession())->getDbgMask
()) == (0x00000080 +0x20000000))) (getItemType()->getSession
())->getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "mergeWith() final status: thisitem: %schanged, otheritem: %schanged (relevant; eqm_none field changes are not indicated)"
, aChangedThis ? "" : "not ", aChangedOther ? "" : "not " ); }
1371 aChangedThis ? "" : "not ",{ if ((getItemType()->getSession()) && (((0x00000080
+0x20000000) & (getItemType()->getSession())->getDbgMask
()) == (0x00000080 +0x20000000))) (getItemType()->getSession
())->getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "mergeWith() final status: thisitem: %schanged, otheritem: %schanged (relevant; eqm_none field changes are not indicated)"
, aChangedThis ? "" : "not ", aChangedOther ? "" : "not " ); }
1372 aChangedOther ? "" : "not "{ if ((getItemType()->getSession()) && (((0x00000080
+0x20000000) & (getItemType()->getSession())->getDbgMask
()) == (0x00000080 +0x20000000))) (getItemType()->getSession
())->getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "mergeWith() final status: thisitem: %schanged, otheritem: %schanged (relevant; eqm_none field changes are not indicated)"
, aChangedThis ? "" : "not ", aChangedOther ? "" : "not " ); }
1373 )){ if ((getItemType()->getSession()) && (((0x00000080
+0x20000000) & (getItemType()->getSession())->getDbgMask
()) == (0x00000080 +0x20000000))) (getItemType()->getSession
())->getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "mergeWith() final status: thisitem: %schanged, otheritem: %schanged (relevant; eqm_none field changes are not indicated)"
, aChangedThis ? "" : "not ", aChangedOther ? "" : "not " ); }
;
1374} // TMultiFieldItem::mergeWith
1375
1376
1377// merge this item with specified item.
1378// Notes:
1379// - specified item is treated as loosing item, this item is winning item
1380// - also updates other item to make sure it is equal to the winning after the merge
1381// returns update status of this and other item. Note that changes of non-relevant fields are
1382// not reported here.
1383void TMultiFieldItem::standardMergeWith(TMultiFieldItem &aItem, bool &aChangedThis, bool &aChangedOther,
1384 int mode,
1385 const std::set<std::string> &aIgnoreFields)
1386{
1387 // same type of multifield, try to merge
1388 for (sInt16 i=0; i<fFieldDefinitionsP->numFields(); i++) {
1389 // Ignore fields if told so by optional MERGEFIELDS() parameter.
1390 if (aIgnoreFields.find(fFieldDefinitionsP->fFields[i].fieldname) != aIgnoreFields.end()) {
1391 continue;
1392 }
1393 // get merge mode
1394 sInt16 sep=fFieldDefinitionsP->fFields[i].mergeMode;
1395 // possible merging is only relevant (=to be reported) for fields that are not eqm_none
1396 bool mergerelevant = fFieldDefinitionsP->fFields[i].eqRelevant!=eqm_none;
1397 // check if available in both items at all
1398 if (
1399 fItemTypeP->getFieldOptions(i)->available && // winning
1400 aItem.fItemTypeP->getFieldOptions(i)->available // loosing
1401 ) {
1402 // fields available in both items
1403 // - get both fields
1404 TItemField &winningField = getFieldRef(i);
1405 TItemField &loosingField = aItem.getFieldRef(i);
1406 // - get assigned status of both fields
1407 bool winning = winningField.isAssigned();
1408 bool loosing = loosingField.isAssigned();
1409 // - now decide what to do
1410 if (sep!=mem_none-1 && mode == MERGE_OPTION_FROM_CONFIG) {
1411 // merge enabled
1412 PDEBUGPRINTFX(DBG_DATA+DBG_CONFLICT,({ if (((0x00000080 +0x20000000) & getDbgMask()) == (0x00000080
+0x20000000)) getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "Field '%s' available and enabled for merging, mode/sep=0x%04hX, %srelevant"
, fFieldDefinitionsP->fFields[i].fieldname.c_str(), sep, mergerelevant
? "" : "NOT " ); }
1413 "Field '%s' available and enabled for merging, mode/sep=0x%04hX, %srelevant",{ if (((0x00000080 +0x20000000) & getDbgMask()) == (0x00000080
+0x20000000)) getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "Field '%s' available and enabled for merging, mode/sep=0x%04hX, %srelevant"
, fFieldDefinitionsP->fFields[i].fieldname.c_str(), sep, mergerelevant
? "" : "NOT " ); }
1414 fFieldDefinitionsP->fFields[i].TCFG_CSTR(fieldname),{ if (((0x00000080 +0x20000000) & getDbgMask()) == (0x00000080
+0x20000000)) getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "Field '%s' available and enabled for merging, mode/sep=0x%04hX, %srelevant"
, fFieldDefinitionsP->fFields[i].fieldname.c_str(), sep, mergerelevant
? "" : "NOT " ); }
1415 sep,{ if (((0x00000080 +0x20000000) & getDbgMask()) == (0x00000080
+0x20000000)) getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "Field '%s' available and enabled for merging, mode/sep=0x%04hX, %srelevant"
, fFieldDefinitionsP->fFields[i].fieldname.c_str(), sep, mergerelevant
? "" : "NOT " ); }
1416 mergerelevant ? "" : "NOT "{ if (((0x00000080 +0x20000000) & getDbgMask()) == (0x00000080
+0x20000000)) getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "Field '%s' available and enabled for merging, mode/sep=0x%04hX, %srelevant"
, fFieldDefinitionsP->fFields[i].fieldname.c_str(), sep, mergerelevant
? "" : "NOT " ); }
1417 )){ if (((0x00000080 +0x20000000) & getDbgMask()) == (0x00000080
+0x20000000)) getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "Field '%s' available and enabled for merging, mode/sep=0x%04hX, %srelevant"
, fFieldDefinitionsP->fFields[i].fieldname.c_str(), sep, mergerelevant
? "" : "NOT " ); }
;
1418 PDEBUGPRINTFX(DBG_DATA+DBG_CONFLICT,({ if (((0x00000080 +0x20000000) & getDbgMask()) == (0x00000080
+0x20000000)) getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "- %sassigned in winning / %sassigned in loosing"
, winning ? "" : "not ", loosing ? "" : "not " ); }
1419 "- %sassigned in winning / %sassigned in loosing",{ if (((0x00000080 +0x20000000) & getDbgMask()) == (0x00000080
+0x20000000)) getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "- %sassigned in winning / %sassigned in loosing"
, winning ? "" : "not ", loosing ? "" : "not " ); }
1420 winning ? "" : "not ",{ if (((0x00000080 +0x20000000) & getDbgMask()) == (0x00000080
+0x20000000)) getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "- %sassigned in winning / %sassigned in loosing"
, winning ? "" : "not ", loosing ? "" : "not " ); }
1421 loosing ? "" : "not "{ if (((0x00000080 +0x20000000) & getDbgMask()) == (0x00000080
+0x20000000)) getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "- %sassigned in winning / %sassigned in loosing"
, winning ? "" : "not ", loosing ? "" : "not " ); }
1422 )){ if (((0x00000080 +0x20000000) & getDbgMask()) == (0x00000080
+0x20000000)) getDbgLogger()->setNextMask(0x00000080 +0x20000000
).DebugPrintfLastMask ( "- %sassigned in winning / %sassigned in loosing"
, winning ? "" : "not ", loosing ? "" : "not " ); }
;
1423 // - if both are unassigned -> nop
1424 if (!winning && !loosing) continue; // test next field
1425 // - if this item has field unassigned and other has it assigned: copy contents
1426 else if (!winning && loosing && (sep==mem_fillempty-2 || sep==mem_addunassigned-3)) {
1427 // assign loosing item's content to non-assigned winning item
1428 getFieldRef(i)=aItem.getFieldRef(i);
1429 #ifdef SYDEBUG2
1430 string ds;
1431 getFieldRef(i).getAsString(ds);
1432 PDEBUGPRINTFX(DBG_DATA+DBG_CONFLICT+DBG_USERDATA,({ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- assigned value '%" ".40" "s' to winning (which had nothing assigned here)"
, ds.c_str() ); }
1433 "- assigned value '%" FMT_LENGTH(".40") "s' to winning (which had nothing assigned here)",{ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- assigned value '%" ".40" "s' to winning (which had nothing assigned here)"
, ds.c_str() ); }
1434 FMT_LENGTH_LIMITED(40,ds.c_str()){ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- assigned value '%" ".40" "s' to winning (which had nothing assigned here)"
, ds.c_str() ); }
1435 )){ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- assigned value '%" ".40" "s' to winning (which had nothing assigned here)"
, ds.c_str() ); }
;
1436 #endif
1437 // count only if relevant and not assigned empty value
1438 // (so empty and unassigned are treated equally)
1439 if (mergerelevant && !aItem.getFieldRef(i).isEmpty())
1440 aChangedThis=true; // merged something into this item
1441 }
1442 else if (winning && loosing) {
1443 // merge loosing field into winning field
1444 if (sep==mem_fillempty-2) {
1445 // only fill up empty winning fields
1446 if (winningField.isEmpty() && !loosingField.isEmpty()) {
1447 // only copy value from loosing if winning is empty
1448 winningField=loosingField;
1449 #ifdef SYDEBUG2
1450 string ds;
1451 winningField.getAsString(ds);
1452 PDEBUGPRINTFX(DBG_DATA+DBG_CONFLICT+DBG_USERDATA,({ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- copied value '%" ".40" "s' from loosing to empty winning"
, ds.c_str() ); }
1453 "- copied value '%" FMT_LENGTH(".40") "s' from loosing to empty winning",{ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- copied value '%" ".40" "s' from loosing to empty winning"
, ds.c_str() ); }
1454 FMT_LENGTH_LIMITED(40,ds.c_str()){ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- copied value '%" ".40" "s' from loosing to empty winning"
, ds.c_str() ); }
1455 )){ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- copied value '%" ".40" "s' from loosing to empty winning"
, ds.c_str() ); }
;
1456 #endif
1457 if (mergerelevant) aChangedThis=true;
1458 }
1459 }
1460 else {
1461 // try real merge (sep might be 0 (mem_concat) or a separator char)
1462 #ifdef SYDEBUG2
1463 string ds1,ds2;
1464 winningField.getAsString(ds1);
1465 loosingField.getAsString(ds2);
1466 PDEBUGPRINTFX(DBG_DATA+DBG_CONFLICT+DBG_USERDATA,({ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- try merging winning value '%" ".40" "s' with loosing value '%"
".40" "s'", ds1.c_str(), ds2.c_str() ); }
1467 "- try merging winning value '%" FMT_LENGTH(".40") "s' with loosing value '%" FMT_LENGTH(".40") "s'",{ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- try merging winning value '%" ".40" "s' with loosing value '%"
".40" "s'", ds1.c_str(), ds2.c_str() ); }
1468 FMT_LENGTH_LIMITED(40,ds1.c_str()),{ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- try merging winning value '%" ".40" "s' with loosing value '%"
".40" "s'", ds1.c_str(), ds2.c_str() ); }
1469 FMT_LENGTH_LIMITED(40,ds2.c_str()){ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- try merging winning value '%" ".40" "s' with loosing value '%"
".40" "s'", ds1.c_str(), ds2.c_str() ); }
1470 )){ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- try merging winning value '%" ".40" "s' with loosing value '%"
".40" "s'", ds1.c_str(), ds2.c_str() ); }
;
1471 #endif
1472 if (winningField.merge(loosingField,sep))
1473 aChangedThis=true;
1474 #ifdef SYDEBUG2
1475 winningField.getAsString(ds1);
1476 PDEBUGPRINTFX(DBG_DATA+DBG_CONFLICT+DBG_USERDATA,({ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( " merged %sthing, winning value is '%" ".40" "s'", aChangedThis
? "some" : "no", ds1.c_str() ); }
1477 " merged %sthing, winning value is '%" FMT_LENGTH(".40") "s'",{ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( " merged %sthing, winning value is '%" ".40" "s'", aChangedThis
? "some" : "no", ds1.c_str() ); }
1478 aChangedThis ? "some" : "no",{ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( " merged %sthing, winning value is '%" ".40" "s'", aChangedThis
? "some" : "no", ds1.c_str() ); }
1479 FMT_LENGTH_LIMITED(40,ds1.c_str()){ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( " merged %sthing, winning value is '%" ".40" "s'", aChangedThis
? "some" : "no", ds1.c_str() ); }
1480 )){ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( " merged %sthing, winning value is '%" ".40" "s'", aChangedThis
? "some" : "no", ds1.c_str() ); }
;
1481 #endif
1482 }
1483 }
1484 } // merge enabled
1485 // with or without merge, loosing fields must be equal to winning ones
1486 // - for non merge-relevant (that is, never-compared) fields,
1487 // just assign winning value to loosing and do not compare (this
1488 // is important to avoid pulling large blobs and strings here -
1489 // assignment just passes the proxy)
1490 if (!mergerelevant) {
1491 // everything is handled by the field assignment mechanisms
1492 if (mode == MERGE_OPTION_CHANGE_THIS) {
1493 winningField = loosingField;
1494 } else {
1495 loosingField = winningField;
1496 }
1497 }
1498 else if (winningField!=loosingField) {
1499 // merge relevant fields will get more sophisticated treatment, such
1500 // as checking if a change has occurred and cutoff detection
1501 #ifdef SYDEBUG2
1502 string wfv,lfv;
1503 winningField.getAsString(wfv);
1504 loosingField.getAsString(lfv);
1505 PDEBUGPRINTFX(DBG_DATA+DBG_CONFLICT+DBG_USERDATA,({ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "Winning and loosing Field '%s' not equal: '%" ".30" "s' <> '%"
".30" "s'", fFieldDefinitionsP->fFields[i].fieldname.c_str
(), wfv.c_str(),lfv.c_str() ); }
1506 "Winning and loosing Field '%s' not equal: '%" FMT_LENGTH(".30") "s' <> '%" FMT_LENGTH(".30") "s'",{ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "Winning and loosing Field '%s' not equal: '%" ".30" "s' <> '%"
".30" "s'", fFieldDefinitionsP->fFields[i].fieldname.c_str
(), wfv.c_str(),lfv.c_str() ); }
1507 fFieldDefinitionsP->fFields[i].TCFG_CSTR(fieldname),{ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "Winning and loosing Field '%s' not equal: '%" ".30" "s' <> '%"
".30" "s'", fFieldDefinitionsP->fFields[i].fieldname.c_str
(), wfv.c_str(),lfv.c_str() ); }
1508 FMT_LENGTH_LIMITED(30,wfv.c_str()),FMT_LENGTH_LIMITED(30,lfv.c_str()){ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "Winning and loosing Field '%s' not equal: '%" ".30" "s' <> '%"
".30" "s'", fFieldDefinitionsP->fFields[i].fieldname.c_str
(), wfv.c_str(),lfv.c_str() ); }
1509 )){ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "Winning and loosing Field '%s' not equal: '%" ".30" "s' <> '%"
".30" "s'", fFieldDefinitionsP->fFields[i].fieldname.c_str
(), wfv.c_str(),lfv.c_str() ); }
;
1510 #endif
1511 // update loosing item, too, unless the winning field is shorter or explicitly requested
1512 if (mode == MERGE_OPTION_CHANGE_THIS ||
1513 loosingField.isShortVers(winningField,fItemTypeP->getFieldOptions(i)->maxsize)) {
1514 // winning field is short version of loosing field -> loosing field is "better", use it
1515 winningField=loosingField;
1516 aChangedThis=true;
1517 }
1518 else {
1519 // standard case, loosing field is replaced by winning field
1520 loosingField=winningField;
1521 aChangedOther=true;
1522 }
1523 // this is some kind of item-level merge as well
1524 #ifdef SYDEBUG2
1525 string ds;
1526 winningField.getAsString(ds);
1527 PDEBUGPRINTFX(DBG_DATA+DBG_CONFLICT+DBG_USERDATA,({ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- updated fields such that both have same value '%" ".40"
"s'", ds.c_str() ); }
1528 "- updated fields such that both have same value '%" FMT_LENGTH(".40") "s'",{ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- updated fields such that both have same value '%" ".40"
"s'", ds.c_str() ); }
1529 FMT_LENGTH_LIMITED(40,ds.c_str()){ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- updated fields such that both have same value '%" ".40"
"s'", ds.c_str() ); }
1530 )){ if (((0x00000080 +0x20000000 +0x01000000) & getDbgMask(
)) == (0x00000080 +0x20000000 +0x01000000)) getDbgLogger()->
setNextMask(0x00000080 +0x20000000 +0x01000000).DebugPrintfLastMask
( "- updated fields such that both have same value '%" ".40"
"s'", ds.c_str() ); }
;
1531 #endif
1532 }
1533 } // field available in both items
1534 } // field loop
1535} // TMultiFieldItem::standardMergeWith
1536
1537#endif // server only
1538
1539#ifdef SYDEBUG2
1540// show item contents for debug
1541void TMultiFieldItem::debugShowItem(uInt32 aDbgMask)
1542{
1543 TFieldListConfig *fielddefsP = getFieldDefinitions();
1544 string val,fshow,oloc,orem;
1545 TFieldOptions *foptP;
1546 TItemField *fldP;
1547
1548 if (PDEBUGTEST(aDbgMask|DBG_DETAILS)(((aDbgMask|0x40000000) & getDbgMask()) == (aDbgMask|0x40000000
))
) {
1549 // very detailed
1550 bool hasdata =
1551 getSyncOp()!=sop_archive_delete &&
1552 getSyncOp()!=sop_soft_delete &&
1553 getSyncOp()!=sop_delete &&
1554 getSyncOp()!=sop_copy &&
1555 getSyncOp()!=sop_move;
1556 // - item header info
1557 PDEBUGPRINTFX(aDbgMask|DBG_DETAILS|DBG_HOT,({ if (((aDbgMask|0x40000000|0x00000001) & getDbgMask()) ==
(aDbgMask|0x40000000|0x00000001)) getDbgLogger()->setNextMask
(aDbgMask|0x40000000|0x00000001).DebugPrintfLastMask ( "Item LocalID='%s', RemoteID='%s', operation=%s%s"
, getLocalID(), getRemoteID(), SyncOpNames[getSyncOp()], hasdata
&& (((aDbgMask|0x01000000) & getDbgMask()) == (aDbgMask
|0x01000000)) ? ", size: [maxlocal,maxremote,actual]" : "" );
}
1558 "Item LocalID='%s', RemoteID='%s', operation=%s%s",{ if (((aDbgMask|0x40000000|0x00000001) & getDbgMask()) ==
(aDbgMask|0x40000000|0x00000001)) getDbgLogger()->setNextMask
(aDbgMask|0x40000000|0x00000001).DebugPrintfLastMask ( "Item LocalID='%s', RemoteID='%s', operation=%s%s"
, getLocalID(), getRemoteID(), SyncOpNames[getSyncOp()], hasdata
&& (((aDbgMask|0x01000000) & getDbgMask()) == (aDbgMask
|0x01000000)) ? ", size: [maxlocal,maxremote,actual]" : "" );
}
1559 getLocalID(),{ if (((aDbgMask|0x40000000|0x00000001) & getDbgMask()) ==
(aDbgMask|0x40000000|0x00000001)) getDbgLogger()->setNextMask
(aDbgMask|0x40000000|0x00000001).DebugPrintfLastMask ( "Item LocalID='%s', RemoteID='%s', operation=%s%s"
, getLocalID(), getRemoteID(), SyncOpNames[getSyncOp()], hasdata
&& (((aDbgMask|0x01000000) & getDbgMask()) == (aDbgMask
|0x01000000)) ? ", size: [maxlocal,maxremote,actual]" : "" );
}
1560 getRemoteID(),{ if (((aDbgMask|0x40000000|0x00000001) & getDbgMask()) ==
(aDbgMask|0x40000000|0x00000001)) getDbgLogger()->setNextMask
(aDbgMask|0x40000000|0x00000001).DebugPrintfLastMask ( "Item LocalID='%s', RemoteID='%s', operation=%s%s"
, getLocalID(), getRemoteID(), SyncOpNames[getSyncOp()], hasdata
&& (((aDbgMask|0x01000000) & getDbgMask()) == (aDbgMask
|0x01000000)) ? ", size: [maxlocal,maxremote,actual]" : "" );
}
1561 SyncOpNames[getSyncOp()],{ if (((aDbgMask|0x40000000|0x00000001) & getDbgMask()) ==
(aDbgMask|0x40000000|0x00000001)) getDbgLogger()->setNextMask
(aDbgMask|0x40000000|0x00000001).DebugPrintfLastMask ( "Item LocalID='%s', RemoteID='%s', operation=%s%s"
, getLocalID(), getRemoteID(), SyncOpNames[getSyncOp()], hasdata
&& (((aDbgMask|0x01000000) & getDbgMask()) == (aDbgMask
|0x01000000)) ? ", size: [maxlocal,maxremote,actual]" : "" );
}
1562 hasdata && PDEBUGTEST(aDbgMask|DBG_USERDATA) ? ", size: [maxlocal,maxremote,actual]" : ""{ if (((aDbgMask|0x40000000|0x00000001) & getDbgMask()) ==
(aDbgMask|0x40000000|0x00000001)) getDbgLogger()->setNextMask
(aDbgMask|0x40000000|0x00000001).DebugPrintfLastMask ( "Item LocalID='%s', RemoteID='%s', operation=%s%s"
, getLocalID(), getRemoteID(), SyncOpNames[getSyncOp()], hasdata
&& (((aDbgMask|0x01000000) & getDbgMask()) == (aDbgMask
|0x01000000)) ? ", size: [maxlocal,maxremote,actual]" : "" );
}
1563 )){ if (((aDbgMask|0x40000000|0x00000001) & getDbgMask()) ==
(aDbgMask|0x40000000|0x00000001)) getDbgLogger()->setNextMask
(aDbgMask|0x40000000|0x00000001).DebugPrintfLastMask ( "Item LocalID='%s', RemoteID='%s', operation=%s%s"
, getLocalID(), getRemoteID(), SyncOpNames[getSyncOp()], hasdata
&& (((aDbgMask|0x01000000) & getDbgMask()) == (aDbgMask
|0x01000000)) ? ", size: [maxlocal,maxremote,actual]" : "" );
}
;
1564 if (!hasdata)
1565 return; // do not show data for delete
1566 if (!PDEBUGTEST(aDbgMask|DBG_USERDATA)(((aDbgMask|0x01000000) & getDbgMask()) == (aDbgMask|0x01000000
))
) {
1567 PDEBUGPRINTFX(aDbgMask|DBG_DETAILS,("*** field data not shown because userdata log is disabled ***")){ if (((aDbgMask|0x40000000) & getDbgMask()) == (aDbgMask
|0x40000000)) getDbgLogger()->setNextMask(aDbgMask|0x40000000
).DebugPrintfLastMask ("*** field data not shown because userdata log is disabled ***"
); }
;
1568 return; // do not show any field data
1569 }
1570 // - fields
1571 fshow.erase();
1572 for (sInt16 k=0; k<fielddefsP->numFields(); k++) {
1573 SYSYNC_TRYtry {
1574 const TFieldDefinition *fdP = &(fielddefsP->fFields[k]);
1575 // get options
1576 oloc="?";
1577 if (fItemTypeP) {
1578 foptP=fItemTypeP->getFieldOptions(k);
1579 if (!foptP->available)
1580 oloc="n/a";
1581 else
1582 StringObjPrintf(oloc,"%ld",(long)foptP->maxsize);
1583 }
1584 orem="?";
1585 if (fTargetItemTypeP) {
1586 foptP=fTargetItemTypeP->getFieldOptions(k);
1587 if (!foptP->available)
1588 orem="n/a";
1589 else
1590 StringObjPrintf(orem,"%ld",(long)foptP->maxsize);
1591 }
1592 // get value (but prevent pulling proxies)
1593 fldP=NULL__null;
1594 size_t n=0; // empty or unknown size
1595 if (isAssigned(k)) {
1596 fldP = getField(k);
1597 val.erase();
1598 n = fldP->StringObjFieldAppend(val,99); // get string representation and size
1599 }
1600 else
1601 val="<unassigned>";
1602 // now show main info
1603 StringObjAppendPrintf(fshow,
1604 "- %2d : %10s %-15s [%4s,%4s,%6ld] : %s\n",
1605 k, // fid
1606 ItemFieldTypeNames[fdP->type], // field type
1607 TCFG_CSTR(fdP->fieldname)fdP->fieldname.c_str(), // field name
1608 oloc.c_str(),
1609 orem.c_str(),
1610 long(n),
1611 val.c_str()
1612 );
1613 // show array contents if any
1614 if (fldP && fldP->isArray()) {
1615 int arridx;
1616 for (arridx=0; arridx<fldP->arraySize(); arridx++) {
1617 // show array elements
1618 TItemField *elemP = fldP->getArrayField(arridx,true);
1619 val.erase();
1620 elemP->StringObjFieldAppend(val,99);
1621 StringObjAppendPrintf(fshow,
1622 " -- element %4d : %s\n",
1623 arridx,
1624 val.c_str()
1625 );
1626 }
1627 } // isArray
1628 }
1629 SYSYNC_CATCH(exception &e)catch(exception &e) {
1630 PDEBUGPRINTFX(DBG_ERROR,("Exception when trying to show field fid=%hd: %s[FLUSH]",k,e.what())){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("Exception when trying to show field fid=%hd: %s[FLUSH]"
,k,e.what()); }
;
1631 SYSYNC_ENDCATCH}
1632 SYSYNC_CATCH(...)catch(...) {
1633 PDEBUGPRINTFX(DBG_ERROR,("Unknown Exception when trying to show field fid=%hd[FLUSH]",k)){ if (((0x00000002) & getDbgMask()) == (0x00000002)) getDbgLogger
()->setNextMask(0x00000002).DebugPrintfLastMask ("Unknown Exception when trying to show field fid=%hd[FLUSH]"
,k); }
;
1634 SYSYNC_ENDCATCH}
1635 } // for all fields
1636 PDEBUGPUTSXX(aDbgMask|DBG_DETAILS|DBG_USERDATA,fshow.c_str(),0,true){ if (((aDbgMask|0x40000000|0x01000000) & getDbgMask()) ==
(aDbgMask|0x40000000|0x01000000)) getDbgLogger()->DebugPuts
( aDbgMask|0x40000000|0x01000000,fshow.c_str(),0,true); }
;
1637 }
1638 else if (PDEBUGTEST(aDbgMask)(((aDbgMask) & getDbgMask()) == (aDbgMask))) {
1639 // single line only
1640 StringObjPrintf(fshow,
1641 "Item locID='%s', RemID='%s', op=%s",
1642 getLocalID(),
1643 getRemoteID(),
1644 SyncOpNames[getSyncOp()]
1645 );
1646 if (!PDEBUGTEST(aDbgMask|DBG_USERDATA)(((aDbgMask|0x01000000) & getDbgMask()) == (aDbgMask|0x01000000
))
) {
1647 fshow+=", *** userdata log disabled ***";
1648 }
1649 else if (
1650 getSyncOp()==sop_archive_delete ||
1651 getSyncOp()==sop_soft_delete ||
1652 getSyncOp()==sop_delete
1653 ) {
1654 // do not show data for delete
1655 }
1656 else {
1657 fshow+=", Fields: ";
1658 for (sInt16 k=0; k<fielddefsP->numFields(); k++) {
1659 if (isAssigned(k)) {
1660 if (!getField(k)->isEmpty() && !getField(k)->hasProxy()) {
1661 getField(k)->StringObjFieldAppend(fshow,20);
1662 fshow+=", ";
1663 }
1664 }
1665 }
1666 }
1667 PDEBUGPUTSX(aDbgMask,fshow.c_str()){ if (((aDbgMask) & getDbgMask()) == (aDbgMask)) getDbgLogger
()->DebugPuts( aDbgMask,fshow.c_str()); }
;
1668 }
1669} // TMultiFieldItem::debugShowItem
1670
1671#endif
1672
1673/* end of TMultiFieldItem implementation */
1674
1675
1676#ifdef DBAPI_TUNNEL_SUPPORT
1677
1678// TMultiFieldItemKey
1679// ==================
1680
1681
1682// set new content item
1683void TMultiFieldItemKey::setItem(TMultiFieldItem *aItemP, bool aPassOwner)
1684{
1685 forgetItem();
1686 fItemP = aItemP;
1687 fOwnsItem = aPassOwner;
1688 fWritten = fItemP; // if we have set an item, this counts as written
1689} // TMultiFieldItemKey::setItem
1690
1691
1692// get FID for specified name
1693sInt16 TMultiFieldItemKey::getFidFor(cAppCharP aName, stringSize aNameSz)
1694{
1695 if (!fItemP) return VARIDX_UNDEFINED-128; // no item, no field is accessible
1696
1697 TFieldListConfig *flcP = fItemP->getFieldDefinitions();
1698
1699 // check for iterator commands first
1700 if (strucmp(aName,VALNAME_FIRST".FIRST")==0) {
1701 fIteratorFid = 0;
1702 if (fIteratorFid<flcP->numFields())
1703 return fIteratorFid;
1704 }
1705 else if (strucmp(aName,VALNAME_NEXT".NEXT")==0) {
1706 if (fIteratorFid<flcP->numFields())
1707 fIteratorFid++;
1708 if (fIteratorFid<flcP->numFields())
1709 return fIteratorFid;
1710 }
1711 else {
1712 return flcP->fieldIndex(aName,aNameSz);
1713 }
1714 // none found
1715 return VARIDX_UNDEFINED-128;
1716} // TMultiFieldItemKey::getFidFor
1717
1718
1719
1720TItemField *TMultiFieldItemKey::getBaseFieldFromFid(sInt16 aFid)
1721{
1722 if (!fItemP) return NULL__null; // no item, no field is accessible
1723 return fItemP->getField(aFid);
1724} // TMultiFieldItemKey::getBaseFieldFromFid
1725
1726
1727bool TMultiFieldItemKey::getFieldNameFromFid(sInt16 aFid, string &aFieldName)
1728{
1729 if (!fItemP) return false; // no item, no field is accessible
1730 // name is field name
1731 TFieldListConfig *flcP = fItemP->getFieldDefinitions();
1732 if (aFid>=0 && aFid<flcP->numFields()) {
1733 aFieldName = flcP->fFields[aFid].fieldname;
1734 return true;
1735 }
1736 // none found
1737 return false;
1738} // TMultiFieldItemKey::getFieldNameFromFid
1739
1740
1741#endif // DBAPI_TUNNEL_SUPPORT
1742
1743
1744} // namespace sysync
1745
1746// eof