thorxmlwrite.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "platform.h"
  14. #include "jlib.hpp"
  15. #include "thorxmlwrite.hpp"
  16. #include "eclrtl.hpp"
  17. #include "rtlkey.hpp"
  18. #include "eclhelper.hpp"
  19. #include "deftype.hpp"
  20. #include "rtlformat.hpp"
  21. #include "rtlbcd.hpp"
  22. CommonFieldProcessor::CommonFieldProcessor(StringBuffer &_result, bool _trim) : result(_result), trim(_trim)
  23. {
  24. }
  25. void CommonFieldProcessor::processString(unsigned len, const char *value, const RtlFieldInfo * field)
  26. {
  27. if (trim)
  28. len = rtlTrimStrLen(len, value);
  29. result.append("'");
  30. outputXmlString(len, value, NULL, result);
  31. result.append("'");
  32. }
  33. void CommonFieldProcessor::processBool(bool value, const RtlFieldInfo * field)
  34. {
  35. outputXmlBool(value, NULL, result);
  36. }
  37. void CommonFieldProcessor::processData(unsigned len, const void *value, const RtlFieldInfo * field)
  38. {
  39. outputXmlData(len, value, NULL, result);
  40. }
  41. void CommonFieldProcessor::processInt(__int64 value, const RtlFieldInfo * field)
  42. {
  43. outputXmlInt(value, NULL, result);
  44. }
  45. void CommonFieldProcessor::processUInt(unsigned __int64 value, const RtlFieldInfo * field)
  46. {
  47. outputXmlUInt(value, NULL, result);
  48. }
  49. void CommonFieldProcessor::processReal(double value, const RtlFieldInfo * field)
  50. {
  51. outputXmlReal(value, NULL, result);
  52. }
  53. void CommonFieldProcessor::processDecimal(const void *value, unsigned digits, unsigned precision, const RtlFieldInfo * field)
  54. {
  55. outputXmlDecimal(value, digits, precision, NULL, result);
  56. }
  57. void CommonFieldProcessor::processUDecimal(const void *value, unsigned digits, unsigned precision, const RtlFieldInfo * field)
  58. {
  59. outputXmlUDecimal(value, digits, precision, NULL, result);
  60. }
  61. void CommonFieldProcessor::processUnicode(unsigned len, const UChar *value, const RtlFieldInfo * field)
  62. {
  63. if (trim)
  64. len = rtlTrimUnicodeStrLen(len, value);
  65. outputXmlUnicode(len, value, NULL, result);
  66. }
  67. void CommonFieldProcessor::processQString(unsigned len, const char *value, const RtlFieldInfo * field)
  68. {
  69. MemoryAttr tempBuffer;
  70. char * temp;
  71. if (len <= 100)
  72. temp = (char *)alloca(len);
  73. else
  74. temp = (char *)tempBuffer.allocate(len);
  75. rtlQStrToStr(len, temp, len, value);
  76. processString(len, temp, field);
  77. }
  78. void CommonFieldProcessor::processUtf8(unsigned len, const char *value, const RtlFieldInfo * field)
  79. {
  80. if (trim)
  81. len = rtlTrimUtf8StrLen(len, value);
  82. outputXmlUtf8(len, value, NULL, result);
  83. }
  84. bool CommonFieldProcessor::processBeginSet(const RtlFieldInfo * field, unsigned numElements, bool isAll, const byte *data)
  85. {
  86. result.append('[');
  87. if (isAll)
  88. result.append("ALL");
  89. return true;
  90. }
  91. bool CommonFieldProcessor::processBeginDataset(const RtlFieldInfo * field, unsigned numRows)
  92. {
  93. result.append('[');
  94. return true;
  95. }
  96. bool CommonFieldProcessor::processBeginRow(const RtlFieldInfo * field)
  97. {
  98. result.append('{');
  99. return true;
  100. }
  101. void CommonFieldProcessor::processEndSet(const RtlFieldInfo * field)
  102. {
  103. result.append(']');
  104. }
  105. void CommonFieldProcessor::processEndDataset(const RtlFieldInfo * field)
  106. {
  107. result.append(']');
  108. }
  109. void CommonFieldProcessor::processEndRow(const RtlFieldInfo * field)
  110. {
  111. result.append('}');
  112. }
  113. //=============================================================================================
  114. // MORE - this function should probably move into IIndexReadContext interface rather than leaking ordinality() and item() out of that interface just for me
  115. void printKeyedValues(StringBuffer &out, IIndexReadContext *segs, IOutputMetaData *rowMeta)
  116. {
  117. unsigned totalKeyedSize = 0;
  118. unsigned numSegs = segs->ordinality();
  119. while (numSegs)
  120. {
  121. IKeySegmentMonitor &seg = *segs->item(numSegs-1);
  122. if (!seg.isWild())
  123. {
  124. totalKeyedSize = seg.getOffset() + seg.getSize();
  125. break;
  126. }
  127. numSegs--;
  128. }
  129. if (numSegs)
  130. {
  131. byte *tempRow = (byte *) alloca(totalKeyedSize);
  132. byte *savedRow = (byte *) alloca(totalKeyedSize);
  133. const RtlFieldInfo * const *fields = rowMeta->queryTypeInfo()->queryFields();
  134. unsigned fieldOffset = 0;
  135. bool inKeyed = false;
  136. bool inWild = false;
  137. for (unsigned segNo = 0; segNo < numSegs; segNo++)
  138. {
  139. IKeySegmentMonitor &seg = *segs->item(segNo);
  140. unsigned segOffset = seg.getOffset();
  141. unsigned segSize = seg.getSize();
  142. while (fieldOffset < segOffset + segSize) // This is trying to cope with the combined case but not sure it completely does
  143. {
  144. assertex(fields[0]->type->isFixedSize());
  145. unsigned curFieldSize = fields[0]->type->size(NULL, NULL);
  146. if (seg.isWild())
  147. {
  148. if (!inWild)
  149. {
  150. if (inKeyed)
  151. {
  152. out.append("),");
  153. inKeyed = false;
  154. }
  155. out.append("WILD(");
  156. inWild = true;
  157. }
  158. else
  159. out.append(',');
  160. out.append(fields[0]->name);
  161. }
  162. else
  163. {
  164. StringBuffer setValues;
  165. CommonFieldProcessor setProcessor(setValues, true);
  166. unsigned numValues = 0;
  167. unsigned subStringLength = 0;
  168. if (!seg.isEmpty())
  169. {
  170. seg.setLow(tempRow);
  171. for (;;)
  172. {
  173. if (numValues)
  174. setValues.append(",");
  175. memcpy(savedRow+segOffset, tempRow+segOffset, segSize);
  176. seg.endRange(tempRow);
  177. if (memcmp(savedRow+segOffset, tempRow+segOffset, segSize) != 0)
  178. {
  179. // Special case - if they differ only in trailing values that are 0 vs 0xff, then it's a substring match...
  180. if (numValues==0 && (fields[0]->type->fieldType & (RFTMkind | RFTMebcdic)) == type_string)
  181. {
  182. unsigned pos;
  183. for (pos = 0; pos < segSize; pos++)
  184. {
  185. if (savedRow[segOffset+pos] != tempRow[segOffset+pos])
  186. break;
  187. }
  188. subStringLength = pos;
  189. for (; pos < segSize; pos++)
  190. {
  191. if (savedRow[segOffset+pos] != 0 || tempRow[segOffset+pos] != 0xff)
  192. {
  193. subStringLength = 0;
  194. break;
  195. }
  196. }
  197. }
  198. fields[0]->process(savedRow + fieldOffset, tempRow, setProcessor);
  199. setValues.append("..");
  200. fields[0]->process(tempRow + fieldOffset, tempRow, setProcessor);
  201. numValues+=2;
  202. }
  203. else
  204. {
  205. fields[0]->process(tempRow + fieldOffset, tempRow, setProcessor);
  206. numValues++;
  207. }
  208. if (!seg.increment(tempRow))
  209. break;
  210. }
  211. }
  212. if (!inKeyed)
  213. {
  214. if (inWild)
  215. {
  216. out.append("),");
  217. inWild = false;
  218. }
  219. out.append("KEYED(");
  220. inKeyed = true;
  221. }
  222. else
  223. out.append(',');
  224. out.append(fields[0]->name);
  225. if (numValues==1)
  226. out.append("=").append(setValues);
  227. else if (subStringLength)
  228. out.appendf("[1..%d]='", subStringLength).append(subStringLength, (char *) savedRow+fieldOffset).append("'");
  229. else
  230. out.append(" IN [").append(setValues).append("]");
  231. }
  232. fieldOffset += curFieldSize;
  233. fields++;
  234. if (!fields[0])
  235. break;
  236. }
  237. }
  238. if (inKeyed || inWild)
  239. out.append(")");
  240. }
  241. else
  242. out.append("UNKEYED");
  243. }
  244. extern thorhelper_decl void convertRowToXML(size32_t & lenResult, char * & result, IOutputMetaData & info, const void * row, unsigned flags)
  245. {
  246. const byte * self = (const byte *)row;
  247. if (flags == (unsigned)-1)
  248. flags = XWFtrim|XWFopt|XWFnoindent;
  249. CommonXmlWriter writer(flags);
  250. info.toXML(self, writer);
  251. //could use detach...
  252. unsigned sizeResult;
  253. rtlStrToStrX(sizeResult, result, writer.length(), writer.str());
  254. lenResult = rtlUtf8Length(sizeResult, result);
  255. }
  256. extern thorhelper_decl void convertRowToJSON(size32_t & lenResult, char * & result, IOutputMetaData & info, const void * row, unsigned flags)
  257. {
  258. const byte * self = (const byte *)row;
  259. if (flags == (unsigned)-1)
  260. flags = XWFtrim|XWFopt|XWFnoindent;
  261. CommonJsonWriter writer(flags);
  262. info.toXML(self, writer);
  263. //could use detach...
  264. unsigned sizeResult;
  265. rtlStrToStrX(sizeResult, result, writer.length(), writer.str());
  266. lenResult = rtlUtf8Length(sizeResult, result);
  267. }