ws_sqlService.cpp 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2014 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 "ws_sqlService.hpp"
  14. #include "exception_util.hpp"
  15. void CwssqlEx::init(IPropertyTree *_cfg, const char *_process, const char *_service)
  16. {
  17. cfg = _cfg;
  18. try
  19. {
  20. ECLFunctions::init();
  21. }
  22. catch (...)
  23. {
  24. throw MakeStringException(-1, "ws_sqlEx: Problem initiating ECLFunctions structure");
  25. }
  26. setWsSqlBuildVersion(hpccBuildInfo.buildTag);
  27. }
  28. bool CwssqlEx::onEcho(IEspContext &context, IEspEchoRequest &req, IEspEchoResponse &resp)
  29. {
  30. resp.setResponse(req.getRequest());
  31. return true;
  32. }
  33. bool CwssqlEx::onGetDBMetaData(IEspContext &context, IEspGetDBMetaDataRequest &req, IEspGetDBMetaDataResponse &resp)
  34. {
  35. context.ensureFeatureAccess(WSSQLACCESS, SecAccess_Read, -1, "WsSQL::GetDBMetaData: Permission denied.");
  36. bool success = false;
  37. StringBuffer username;
  38. context.getUserID(username);
  39. const char* passwd = context.queryPassword();
  40. bool includetables = req.getIncludeTables();
  41. if (includetables)
  42. {
  43. Owned<HPCCFileCache> tmpHPCCFileCache = HPCCFileCache::createFileCache(username.str(), passwd);
  44. tmpHPCCFileCache->populateTablesResponse(resp, req.getTableFilter());
  45. resp.setTableCount(resp.getTables().length());
  46. }
  47. bool includeStoredProcs = req.getIncludeStoredProcedures();
  48. if (includeStoredProcs)
  49. {
  50. const char * querysetfilter = req.getQuerySet();
  51. #ifdef _CONTAINERIZED
  52. ESPLOG(LogNormal, "WsSQL: getting containerTargetClusters...");
  53. Owned<IStringIterator> targets = getContainerTargetClusters(nullptr, nullptr);
  54. #else
  55. ESPLOG(LogNormal, "WsSQL-legacy: getting targetClusters...");
  56. Owned<IStringIterator> targets = getTargetClusters(nullptr, nullptr);
  57. #endif
  58. IArrayOf<IEspHPCCQuerySet> pquerysets;
  59. SCMStringBuffer target;
  60. ForEach(*targets)
  61. {
  62. const char *setname = targets->str(target).str();
  63. if ( querysetfilter && *querysetfilter && stricmp(setname, querysetfilter)!=0)
  64. continue;
  65. Owned<IEspHPCCQuerySet> pqset = createHPCCQuerySet();
  66. pqset->setName(setname);
  67. pquerysets.append(*pqset.getLink());
  68. Owned<IPropertyTree> settree = getQueryRegistry(setname, true);
  69. if (settree == NULL)
  70. continue;
  71. IArrayOf<IEspPublishedQuery> queries;
  72. Owned<IPropertyTreeIterator> iter = settree->getElements("Query");
  73. ForEach(*iter)
  74. {
  75. const char * id = iter->query().queryProp("@id");
  76. const char * qname = iter->query().queryProp("@name");
  77. const char * wuid = iter->query().queryProp("@wuid");
  78. if (qname && *qname && wuid && *wuid)
  79. {
  80. StringBuffer resp;
  81. Owned<IEspPublishedQuery> pubQuery = createPublishedQuery();
  82. pubQuery->setName(qname);
  83. pubQuery->setId(id);
  84. pubQuery->setWuid(wuid);
  85. pubQuery->setSuspended(iter->query().getPropBool("@suspended"));
  86. Owned<IEspQuerySignature> querysignature = createQuerySignature();
  87. IArrayOf<IEspHPCCColumn> inparams;
  88. IArrayOf<IEspOutputDataset> resultsets;
  89. WsEclWuInfo wsinfo(wuid, setname, qname, username, passwd);
  90. Owned<IResultSetFactory> resultSetFactory(getResultSetFactory(username, passwd));
  91. //Each published query can have multiple results (datasets)
  92. IConstWUResultIterator &results = wsinfo.ensureWorkUnit()->getResults();
  93. ForEach(results)
  94. {
  95. Owned<IEspOutputDataset> outputdataset = createOutputDataset();
  96. IArrayOf<IEspHPCCColumn> outparams;
  97. IConstWUResult &result = results.query();
  98. SCMStringBuffer resultName;
  99. result.getResultName(resultName);
  100. outputdataset->setName(resultName.s.str());
  101. Owned<IResultSetMetaData> meta = resultSetFactory->createResultSetMeta(&result);
  102. //Each result dataset can have multiple result columns
  103. int columncount = meta->getColumnCount();
  104. for (int i = 0; i < columncount; i++)
  105. {
  106. Owned<IEspHPCCColumn> col = createHPCCColumn();
  107. SCMStringBuffer columnLabel;
  108. meta->getColumnLabel(columnLabel,i);
  109. col->setName(columnLabel.str());
  110. SCMStringBuffer eclType;
  111. meta->getColumnEclType(eclType, i);
  112. col->setType(eclType.str());
  113. outparams.append(*col.getLink());
  114. }
  115. outputdataset->setOutParams(outparams);
  116. resultsets.append(*outputdataset.getLink());
  117. }
  118. //Each query can have multiple input parameters
  119. IConstWUResultIterator &vars = wsinfo.ensureWorkUnit()->getVariables();
  120. ForEach(vars)
  121. {
  122. Owned<IEspHPCCColumn> col = createHPCCColumn();
  123. IConstWUResult &var = vars.query();
  124. SCMStringBuffer varname;
  125. var.getResultName(varname);
  126. col->setName(varname.str());
  127. Owned<IResultSetMetaData> meta = resultSetFactory->createResultSetMeta(&var);
  128. SCMStringBuffer eclType;
  129. meta->getColumnEclType(eclType, 0);
  130. col->setType(eclType.str());
  131. inparams.append(*col.getLink());
  132. }
  133. querysignature->setInParams(inparams);
  134. querysignature->setResultSets(resultsets);
  135. pubQuery->setSignature(*querysignature.getLink());
  136. queries.append(*pubQuery.getLink());
  137. }
  138. }
  139. pqset->setQuerySetQueries(queries);
  140. IArrayOf<IEspQuerySetAliasMap> aliases;
  141. Owned<IPropertyTreeIterator> aliasiter = settree->getElements("Alias");
  142. ForEach(*aliasiter)
  143. {
  144. Owned<IEspQuerySetAliasMap> alias = createQuerySetAliasMap();
  145. const char * qname;
  146. const char * id;
  147. id = aliasiter->query().queryProp("@id");
  148. qname = aliasiter->query().queryProp("@name");
  149. alias->setId(id);
  150. alias->setName(qname);
  151. aliases.append(*alias.getLink());
  152. }
  153. pqset->setQuerySetAliases(aliases);
  154. }
  155. resp.setQuerySets(pquerysets);
  156. }
  157. bool includeTargetClusters = req.getIncludeTargetClusters();
  158. if (includeTargetClusters)
  159. {
  160. try
  161. {
  162. StringArray dfuclusters;
  163. #ifdef _CONTAINERIZED
  164. ESPLOG(LogNormal, "WsSQL: getting containerTargetClusters...");
  165. Owned<IStringIterator> targets = getContainerTargetClusters(nullptr, nullptr);
  166. SCMStringBuffer target;
  167. ForEach(*targets)
  168. {
  169. const char *setname = targets->str(target).str();
  170. ESPLOG(LogNormal, "WsSQL: found containerTargetClusters: %s", setname);
  171. dfuclusters.append(setname);
  172. }
  173. #else
  174. ESPLOG(LogNormal, "WsSQL-legacy: getting getTargetClusterList...");
  175. CTpWrapper topologyWrapper;
  176. IArrayOf<IEspTpLogicalCluster> clusters;
  177. topologyWrapper.getTargetClusterList(clusters, req.getClusterType(), NULL);
  178. ForEachItemIn(k, clusters)
  179. {
  180. IEspTpLogicalCluster& cluster = clusters.item(k);
  181. dfuclusters.append(cluster.getName());
  182. }
  183. #endif
  184. resp.setClusterNames(dfuclusters);
  185. }
  186. catch(IException* e)
  187. {
  188. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  189. }
  190. }
  191. return success;
  192. }
  193. bool CwssqlEx::onGetDBSystemInfo(IEspContext &context, IEspGetDBSystemInfoRequest &req, IEspGetDBSystemInfoResponse &resp)
  194. {
  195. bool success = false;
  196. resp.setName("HPCC Systems");
  197. context.ensureFeatureAccess(WSSQLACCESS, SecAccess_Access, -1, "WsSQL::GetDBSystemInfo: Permission denied.");
  198. try
  199. {
  200. const char* build_ver = getBuildVersion();
  201. if (build_ver && *build_ver)
  202. {
  203. StringBuffer project;
  204. StringBuffer major;
  205. StringBuffer minor;
  206. StringBuffer point;
  207. StringBuffer maturity;
  208. //community_4.1.0-trunk1-Debug[heads/wssql-0-gb9e351-dirty
  209. const char * tail = build_ver;
  210. while (tail && *tail != '_')
  211. project.append(*tail++);
  212. tail++;
  213. while (tail && *tail != '.')
  214. major.append(*tail++);
  215. resp.setMajor(major.str());
  216. tail++;
  217. while (tail && *tail != '.')
  218. minor.append(*tail++);
  219. resp.setMinor(minor.str());
  220. tail++;
  221. while (tail && *tail != '-')
  222. point.append(*tail++);
  223. resp.setPoint(point.str());
  224. if (req.getIncludeAll())
  225. {
  226. resp.setFullVersion(build_ver);
  227. resp.setProject(project.str());
  228. tail++;
  229. while (tail && *tail != '-' && *tail != '[')
  230. maturity.append(*tail++);
  231. resp.setMaturity(maturity.str());
  232. }
  233. }
  234. const char* wssqlbuild_ver = getWsSqlBuildVersion();
  235. if (wssqlbuild_ver && *wssqlbuild_ver)
  236. {
  237. StringBuffer major;
  238. StringBuffer minor;
  239. StringBuffer point;
  240. StringBuffer maturity;
  241. //5.4.0-trunk1-Debug[heads/wssql-0-gb9e351-dirty
  242. const char * tail = wssqlbuild_ver;
  243. while (tail && *tail != '.')
  244. major.append(*tail++);
  245. resp.setWsSQLMajor(major.str());
  246. tail++;
  247. while (tail && *tail != '.')
  248. minor.append(*tail++);
  249. resp.setWsSQLMinor(minor.str());
  250. tail++;
  251. while (tail && *tail != '-')
  252. point.append(*tail++);
  253. resp.setWsSQLPoint(point.str());
  254. if (req.getIncludeAll())
  255. {
  256. resp.setWsSQLFullVersion(wssqlbuild_ver);
  257. tail++;
  258. while (tail && *tail != '-' && *tail != '[')
  259. maturity.append(*tail++);
  260. resp.setWsSQLMaturity(maturity.str());
  261. }
  262. success = true;
  263. }
  264. }
  265. catch (...)
  266. {
  267. IERRLOG("Error Parsing HPCC and/or WsSQL Version string.");
  268. }
  269. return success;
  270. }
  271. void printTree(pANTLR3_BASE_TREE t, int indent)
  272. {
  273. pANTLR3_BASE_TREE child = NULL;
  274. int children = 0;
  275. char * tokenText = NULL;
  276. string ind = "";
  277. int i = 0;
  278. if ( t != NULL )
  279. {
  280. children = t->getChildCount(t);
  281. for ( i = 0; i < indent; i++ )
  282. ind += " ";
  283. for ( i = 0; i < children; i++ )
  284. {
  285. pANTLR3_BASE_TREE child = (pANTLR3_BASE_TREE)(t->getChild(t, i));
  286. ANTLR3_UINT32 tokenType = child->getType(child);
  287. tokenText = (char *)child->toString(child)->chars;
  288. fprintf(stderr, "%s%s\n", ind.c_str(), tokenText);
  289. if (tokenType == ANTLR3_TOKEN_EOF)
  290. break;
  291. printTree(child, indent+1);
  292. }
  293. }
  294. }
  295. void myDisplayRecognitionError (pANTLR3_BASE_RECOGNIZER recognizer,pANTLR3_UINT8 * tokenNames)
  296. {
  297. StringBuffer errorMessage;
  298. pANTLR3_PARSER parser = NULL;
  299. pANTLR3_TREE_PARSER tparser = NULL;
  300. pANTLR3_INT_STREAM is;
  301. pANTLR3_STRING ttext;
  302. pANTLR3_EXCEPTION ex;
  303. pANTLR3_COMMON_TOKEN theToken;
  304. pANTLR3_BASE_TREE theBaseTree;
  305. pANTLR3_COMMON_TREE theCommonTree;
  306. ex = recognizer->state->exception;
  307. ttext = nullptr;
  308. errorMessage.append("Error while parsing");
  309. if (ex)
  310. {
  311. errorMessage.appendf(": ANTLR Error %d : %s", ex->type, (pANTLR3_UINT8)(ex->message));
  312. switch (recognizer->type)
  313. {
  314. case ANTLR3_TYPE_PARSER:
  315. {
  316. parser = (pANTLR3_PARSER) (recognizer->super);
  317. is = parser->tstream->istream;
  318. theToken = (pANTLR3_COMMON_TOKEN)(ex->token);
  319. if (theToken)
  320. {
  321. ttext = theToken->toString(theToken);
  322. if (theToken->type == ANTLR3_TOKEN_EOF)
  323. errorMessage.append(", at <EOF>");
  324. else
  325. errorMessage.appendf("\n Near %s\n ", ttext == nullptr ? (pANTLR3_UINT8)"<no text for the token>" : ttext->chars);
  326. }
  327. break;
  328. }
  329. case ANTLR3_TYPE_TREE_PARSER:
  330. {
  331. tparser = (pANTLR3_TREE_PARSER) (recognizer->super);
  332. is = tparser->ctnstream->tnstream->istream;
  333. theBaseTree = (pANTLR3_BASE_TREE)(ex->token);
  334. if (theBaseTree)
  335. {
  336. ttext = theBaseTree->toStringTree(theBaseTree);
  337. theCommonTree = (pANTLR3_COMMON_TREE) theBaseTree->super;
  338. if (theCommonTree != nullptr)
  339. theToken = (pANTLR3_COMMON_TOKEN) theBaseTree->getToken(theBaseTree);
  340. errorMessage.appendf( ", at offset %d", theBaseTree->getCharPositionInLine(theBaseTree));
  341. errorMessage.appendf( ", near %s", ttext->chars);
  342. }
  343. break;
  344. }
  345. default:
  346. //errorMessage.appendf("Base recognizer function displayRecognitionError called by unknown parser type - provide override for this function\n");
  347. return;
  348. break;
  349. }
  350. switch (ex->type)
  351. {
  352. case ANTLR3_UNWANTED_TOKEN_EXCEPTION:
  353. {
  354. // Indicates that the recognizer was fed a token which seesm to be
  355. // spurious input. We can detect this when the token that follows
  356. // this unwanted token would normally be part of the syntactically
  357. // correct stream. Then we can see that the token we are looking at
  358. // is just something that should not be there and throw this exception.
  359. //
  360. if (tokenNames == nullptr)
  361. {
  362. errorMessage.appendf( " : Extraneous input...");
  363. }
  364. else
  365. {
  366. if (ex->expecting == ANTLR3_TOKEN_EOF)
  367. errorMessage.appendf(" : Extraneous input - expected <EOF>\n");
  368. else
  369. errorMessage.appendf(" : Extraneous input - expected %s ...\n", tokenNames[ex->expecting]);
  370. }
  371. break;
  372. }
  373. case ANTLR3_MISSING_TOKEN_EXCEPTION:
  374. {
  375. // Indicates that the recognizer detected that the token we just
  376. // hit would be valid syntactically if preceeded by a particular
  377. // token. Perhaps a missing ';' at line end or a missing ',' in an
  378. // expression list, and such like.
  379. //
  380. if (tokenNames == nullptr)
  381. {
  382. errorMessage.appendf( " : Missing token (%d)...\n", ex->expecting);
  383. }
  384. else
  385. {
  386. if (ex->expecting == ANTLR3_TOKEN_EOF)
  387. errorMessage.appendf( " : Missing <EOF>\n");
  388. else
  389. errorMessage.appendf( " : Missing %s \n", tokenNames[ex->expecting]);
  390. }
  391. break;
  392. }
  393. case ANTLR3_RECOGNITION_EXCEPTION:
  394. {
  395. // Indicates that the recognizer received a token
  396. // in the input that was not predicted. This is the basic exception type
  397. // from which all others are derived. So we assume it was a syntax error.
  398. // You may get this if there are not more tokens and more are needed
  399. // to complete a parse for instance.
  400. //
  401. errorMessage.appendf( " : syntax error...\n");
  402. break;
  403. }
  404. case ANTLR3_MISMATCHED_TOKEN_EXCEPTION:
  405. {
  406. // We were expecting to see one thing and got another. This is the
  407. // most common error if we coudl not detect a missing or unwanted token.
  408. // Here you can spend your efforts to
  409. // derive more useful error messages based on the expected
  410. // token set and the last token and so on. The error following
  411. // bitmaps do a good job of reducing the set that we were looking
  412. // for down to something small. Knowing what you are parsing may be
  413. // able to allow you to be even more specific about an error.
  414. //
  415. if (tokenNames == NULL)
  416. {
  417. errorMessage.appendf(" : syntax error...\n");
  418. }
  419. else
  420. {
  421. if (ex->expecting == ANTLR3_TOKEN_EOF)
  422. errorMessage.appendf(" : expected <EOF>\n");
  423. else
  424. errorMessage.appendf(" : expected %s ...\n", tokenNames[ex->expecting]);
  425. }
  426. break;
  427. }
  428. case ANTLR3_NO_VIABLE_ALT_EXCEPTION:
  429. {
  430. // We could not pick any alt decision from the input given
  431. // so god knows what happened - however when you examine your grammar,
  432. // you should. It means that at the point where the current token occurred
  433. // that the DFA indicates nowhere to go from here.
  434. //
  435. errorMessage.appendf(" : cannot match to any predicted input...\n");
  436. break;
  437. }
  438. case ANTLR3_MISMATCHED_SET_EXCEPTION:
  439. {
  440. ANTLR3_UINT32 count;
  441. ANTLR3_UINT32 bit;
  442. ANTLR3_UINT32 size;
  443. ANTLR3_UINT32 numbits;
  444. pANTLR3_BITSET errBits;
  445. // This means we were able to deal with one of a set of
  446. // possible tokens at this point, but we did not see any
  447. // member of that set.
  448. errorMessage.appendf( " : unexpected input...\n expected one of : ");
  449. // What tokens could we have accepted at this point in the parse?
  450. count = 0;
  451. errBits = antlr3BitsetLoad (ex->expectingSet);
  452. numbits = errBits->numBits (errBits);
  453. size = errBits->size (errBits);
  454. if (size > 0)
  455. {
  456. // However many tokens we could have dealt with here, it is usually
  457. // not useful to print ALL of the set here. I arbitrarily chose 8
  458. // here, but you should do whatever makes sense for you of course.
  459. // No token number 0, so look for bit 1 and on.
  460. for (bit = 1; bit < numbits && count < 8 && count < size; bit++)
  461. {
  462. if (tokenNames[bit])
  463. {
  464. errorMessage.appendf( "%s%s", count > 0 ? ", " : "", tokenNames[bit]);
  465. count++;
  466. }
  467. }
  468. errorMessage.appendf( "\n");
  469. }
  470. else
  471. {
  472. errorMessage.appendf( "Unknown parsing error.\n");
  473. }
  474. break;
  475. }
  476. case ANTLR3_EARLY_EXIT_EXCEPTION:
  477. {
  478. // We entered a loop requiring a number of token sequences
  479. // but found a token that ended that sequence earlier than
  480. // we should have done.
  481. errorMessage.appendf( " : missing elements...\n");
  482. break;
  483. }
  484. default:
  485. {
  486. // We don't handle any other exceptions here, but you can
  487. // if you wish. If we get an exception that hits this point
  488. // then we are just going to report what we know about the
  489. // token.
  490. //
  491. errorMessage.appendf( " : unrecognized syntax...\n");
  492. break;
  493. }
  494. }
  495. }
  496. throw MakeStringException(-1, "%s", errorMessage.str());
  497. }
  498. HPCCSQLTreeWalker * CwssqlEx::parseSQL(IEspContext &context, StringBuffer & sqltext, bool attemptParameterization)
  499. {
  500. int limit = -1;
  501. pHPCCSQLLexer hpccSqlLexer = NULL;
  502. pANTLR3_COMMON_TOKEN_STREAM sqlTokens = NULL;
  503. pHPCCSQLParser hpccSqlParser = NULL;
  504. pANTLR3_BASE_TREE sqlAST = NULL;
  505. pANTLR3_INPUT_STREAM sqlInputStream = NULL;
  506. Owned<HPCCSQLTreeWalker> hpccSqlTreeWalker;
  507. try
  508. {
  509. if (sqltext.length() <= 0)
  510. throw MakeStringException(-1, "Empty SQL String detected.");
  511. pANTLR3_UINT8 input_string = (pANTLR3_UINT8)sqltext.str();
  512. pANTLR3_INPUT_STREAM sqlinputstream = antlr3StringStreamNew(input_string,
  513. ANTLR3_ENC_8BIT,
  514. sqltext.length(),
  515. (pANTLR3_UINT8)"SQL INPUT");
  516. pHPCCSQLLexer hpccsqllexer = HPCCSQLLexerNew(sqlinputstream);
  517. //hpccSqlLexer->pLexer->rec->displayRecognitionError = myDisplayRecognitionError;
  518. //ANTLR3_UINT32 lexerrors = hpccsqllexer->pLexer->rec->getNumberOfSyntaxErrors(hpccsqllexer->pLexer->rec);
  519. //if (lexerrors > 0)
  520. // throw MakeStringException(-1, "HPCCSQL Lexer reported %d error(s), request aborted.", lexerrors);
  521. pANTLR3_COMMON_TOKEN_STREAM sqltokens = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(hpccsqllexer));
  522. if (sqltokens == NULL)
  523. {
  524. throw MakeStringException(-1, "Out of memory trying to allocate ANTLR HPCCSQLParser token stream.");
  525. }
  526. pHPCCSQLParser hpccsqlparser = HPCCSQLParserNew(sqltokens);
  527. //#if not defined(_DEBUG)
  528. hpccsqlparser->pParser->rec->displayRecognitionError = myDisplayRecognitionError;
  529. //#endif
  530. pANTLR3_BASE_TREE sqlAST = (hpccsqlparser->root_statement(hpccsqlparser)).tree;
  531. ANTLR3_UINT32 parserrors = hpccsqlparser->pParser->rec->getNumberOfSyntaxErrors(hpccsqlparser->pParser->rec);
  532. if (parserrors > 0)
  533. throw MakeStringException(-1, "HPCCSQL Parser reported %d error(s), request aborted.", parserrors);
  534. #if defined(_DEBUG)
  535. printTree(sqlAST, 0);
  536. #endif
  537. hpccSqlTreeWalker.setown(new HPCCSQLTreeWalker(sqlAST, context, attemptParameterization));
  538. hpccsqlparser->free(hpccsqlparser);
  539. sqltokens->free(sqltokens);
  540. hpccsqllexer->free(hpccsqllexer);
  541. sqlinputstream->free(sqlinputstream);
  542. }
  543. catch(IException* e)
  544. {
  545. try
  546. {
  547. if (hpccSqlParser)
  548. hpccSqlParser->free(hpccSqlParser);
  549. if (sqlTokens)
  550. sqlTokens->free(sqlTokens);
  551. if (hpccSqlLexer)
  552. hpccSqlLexer->free(hpccSqlLexer);
  553. if (sqlInputStream)
  554. sqlInputStream->free(sqlInputStream);
  555. hpccSqlTreeWalker.clear();
  556. }
  557. catch (...)
  558. {
  559. IERRLOG("!!! Unable to free HPCCSQL parser/lexer objects.");
  560. }
  561. //All IExceptions get bubbled up
  562. throw e;
  563. }
  564. catch(...)
  565. {
  566. try
  567. {
  568. if (hpccSqlParser)
  569. hpccSqlParser->free(hpccSqlParser);
  570. if (sqlTokens)
  571. sqlTokens->free(sqlTokens);
  572. if (hpccSqlLexer)
  573. hpccSqlLexer->free(hpccSqlLexer);
  574. if (sqlInputStream)
  575. sqlInputStream->free(sqlInputStream);
  576. hpccSqlTreeWalker.clear();
  577. }
  578. catch (...)
  579. {
  580. IERRLOG("!!! Unable to free HPCCSQL parser/lexer objects.");
  581. }
  582. //All other unexpected exceptions are reported as generic ecl generation error.
  583. throw MakeStringException(-1, "Error generating ECL code.");
  584. }
  585. return hpccSqlTreeWalker.getLink();
  586. }
  587. bool CwssqlEx::getWUResult(IEspContext &context, const char * wuid, StringBuffer &result, unsigned start, unsigned count, int sequence, const char * dsname, const char * schemaname)
  588. {
  589. context.addTraceSummaryTimeStamp(LogMin, "StrtgetReslts");
  590. if (wuid && *wuid)
  591. {
  592. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  593. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid, false);
  594. if (!cw)
  595. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT,"Cannot open workunit %s.", wuid);
  596. SCMStringBuffer stateDesc;
  597. switch (cw->getState())
  598. {
  599. case WUStateCompleted:
  600. case WUStateFailed:
  601. case WUStateUnknown:
  602. case WUStateCompiled:
  603. {
  604. StringBufferAdaptor resultXML(result);
  605. Owned<IResultSetFactory> factory = getResultSetFactory(context.queryUserId(), context.queryPassword());
  606. Owned<INewResultSet> nr = factory->createNewResultSet(wuid, sequence, NULL);
  607. if (nr.get())
  608. {
  609. context.addTraceSummaryTimeStamp(LogMax, "strtgetXMLRslts");
  610. getResultXml(resultXML, nr.get(), dsname, start, count, schemaname);
  611. context.addTraceSummaryTimeStamp(LogMax, "endgetXMLRslts");
  612. }
  613. else
  614. return false;
  615. break;
  616. }
  617. default:
  618. break;
  619. }
  620. context.addTraceSummaryTimeStamp(LogMin, "ExitgetRslts");
  621. return true;
  622. }
  623. context.addTraceSummaryTimeStamp(LogMin, "ExitgetRslts");
  624. return false;
  625. }
  626. bool CwssqlEx::onSetRelatedIndexes(IEspContext &context, IEspSetRelatedIndexesRequest &req, IEspSetRelatedIndexesResponse &resp)
  627. {
  628. context.ensureFeatureAccess(WSSQLACCESS, SecAccess_Write, -1, "WsSQL::SetRelatedIndexes: Permission denied.");
  629. StringBuffer username;
  630. context.getUserID(username);
  631. const char* passwd = context.queryPassword();
  632. IArrayOf<IConstRelatedIndexSet>& relatedindexSets = req.getRelatedIndexSets();
  633. if (relatedindexSets.length() == 0)
  634. throw MakeStringException(-1, "WsSQL::SetRelatedIndexes empty request detected.");
  635. ForEachItemIn(relatedindexsetindex, relatedindexSets)
  636. {
  637. IConstRelatedIndexSet &relatedIndexSet = relatedindexSets.item(relatedindexsetindex);
  638. const char * fileName = relatedIndexSet.getFileName();
  639. if (!fileName || !*fileName)
  640. throw MakeStringException(-1, "WsSQL::SetRelatedIndexes error: Empty file name detected.");
  641. StringArray& indexHints = relatedIndexSet.getIndexes();
  642. int indexHintsCount = indexHints.length();
  643. if (indexHintsCount > 0)
  644. {
  645. Owned<HPCCFile> file = HPCCFileCache::fetchHpccFileByName(fileName,username.str(), passwd, false, false);
  646. if (!file)
  647. throw MakeStringException(-1, "WsSQL::SetRelatedIndexes error: could not find file: %s.", fileName);
  648. StringBuffer description;
  649. StringBuffer currentIndexes;
  650. description = file->getDescription();
  651. HPCCFile::parseOutRelatedIndexes(description, currentIndexes);
  652. description.append("\nXDBC:RelIndexes=[");
  653. for(int indexHintIndex = 0; indexHintIndex < indexHintsCount; indexHintIndex++)
  654. {
  655. description.appendf("%s%c", indexHints.item(indexHintIndex), (indexHintIndex < indexHintsCount-1 ? ';' : ' '));
  656. }
  657. description.append("]\n");
  658. HPCCFileCache::updateHpccFileDescription(fileName, username, passwd, description.str());
  659. file->setDescription(description.str());
  660. }
  661. }
  662. resp.setRelatedIndexSets(relatedindexSets);
  663. return true;
  664. }
  665. bool CwssqlEx::onGetRelatedIndexes(IEspContext &context, IEspGetRelatedIndexesRequest &req, IEspGetRelatedIndexesResponse &resp)
  666. {
  667. try
  668. {
  669. context.ensureFeatureAccess(WSSQLACCESS, SecAccess_Read, -1, "WsSQL::GetRelatedIndexes: Permission denied.");
  670. StringArray& filenames = req.getFileNames();
  671. if (filenames.length() == 0)
  672. throw MakeStringException(-1, "WsSQL::GetRelatedIndexes error: No filenames detected");
  673. StringBuffer username;
  674. context.getUserID(username);
  675. const char* passwd = context.queryPassword();
  676. IArrayOf<IEspRelatedIndexSet> relatedindexSets;
  677. ForEachItemIn(filenameindex, filenames)
  678. {
  679. const char * fileName = filenames.item(filenameindex);
  680. Owned<HPCCFile> file = HPCCFileCache::fetchHpccFileByName(fileName,username.str(), passwd, false, false);
  681. if (file)
  682. {
  683. StringArray indexHints;
  684. file->getRelatedIndexes(indexHints);
  685. Owned<IEspRelatedIndexSet> relatedIndexSet = createRelatedIndexSet("", "");
  686. relatedIndexSet->setFileName(fileName);
  687. relatedIndexSet->setIndexes(indexHints);
  688. relatedindexSets.append(*relatedIndexSet.getLink());
  689. }
  690. }
  691. resp.setRelatedIndexSets(relatedindexSets);
  692. }
  693. catch(IException* e)
  694. {
  695. FORWARDEXCEPTION(context, e, -1);
  696. }
  697. return true;
  698. }
  699. void CwssqlEx::processMultipleClusterOption(StringArray & clusters, const char * targetcluster, StringBuffer & hashoptions)
  700. {
  701. int clusterscount = clusters.length();
  702. if (clusterscount > 0)
  703. {
  704. hashoptions.appendf("\n#OPTION('AllowedClusters', '%s", targetcluster);
  705. ForEachItemIn(i,clusters)
  706. {
  707. validateTargetName(clusters.item(i));
  708. hashoptions.appendf(",%s", clusters.item(i));
  709. }
  710. hashoptions.append("');\n#OPTION('AllowAutoQueueSwitch', TRUE);\n\n");
  711. }
  712. }
  713. bool CwssqlEx::onExecuteSQL(IEspContext &context, IEspExecuteSQLRequest &req, IEspExecuteSQLResponse &resp)
  714. {
  715. try
  716. {
  717. context.addTraceSummaryTimeStamp(LogMin, "StrtOnExecuteSQL");
  718. context.ensureFeatureAccess(WSSQLACCESS, SecAccess_Write, -1, "WsSQL::ExecuteSQL: Permission denied.");
  719. double version = context.getClientVersion();
  720. StringBuffer sqltext;
  721. StringBuffer ecltext;
  722. StringBuffer username;
  723. context.getUserID(username);
  724. const char* passwd = context.queryPassword();
  725. sqltext.set(req.getSqlText());
  726. if (sqltext.length() <= 0)
  727. throw MakeStringException(1,"Empty SQL request.");
  728. const char * cluster = req.getTargetCluster();
  729. StringBuffer hashoptions;
  730. if (version > 3.03)
  731. {
  732. StringArray & alternates = req.getAlternateClusters();
  733. if (alternates.length() > 0)
  734. processMultipleClusterOption(alternates, cluster, hashoptions);
  735. }
  736. SCMStringBuffer compiledwuid;
  737. int resultLimit = req.getResultLimit();
  738. __int64 resultWindowStart = req.getResultWindowStart();
  739. __int64 resultWindowCount = req.getResultWindowCount();
  740. if (resultWindowStart < 0 || resultWindowCount <0 )
  741. throw MakeStringException(-1,"Invalid result window value");
  742. bool clonable = false;
  743. bool cacheeligible = (version > 3.04 ) ? !req.getIgnoreCache() : true;
  744. Owned<HPCCSQLTreeWalker> parsedSQL;
  745. ESPLOG(LogNormal, "WsSQL: Parsing sql query...");
  746. parsedSQL.setown(parseSQL(context, sqltext));
  747. ESPLOG(LogNormal, "WsSQL: Finished parsing sql query...");
  748. SQLQueryType querytype = parsedSQL->getSqlType();
  749. if (querytype == SQLTypeCall)
  750. {
  751. if (strlen(parsedSQL->getQuerySetName())==0)
  752. {
  753. if (strlen(req.getTargetQuerySet())==0)
  754. throw MakeStringException(-1,"Missing Target QuerySet.");
  755. else
  756. parsedSQL->setQuerySetName(req.getTargetQuerySet());
  757. }
  758. ESPLOG(LogMax, "WsSQL: Processing call query...");
  759. WsEclWuInfo wsinfo("", parsedSQL->getQuerySetName(), parsedSQL->getStoredProcName(), username.str(), passwd);
  760. compiledwuid.set(wsinfo.ensureWuid());
  761. clonable = true;
  762. }
  763. else if (querytype == SQLTypeCreateAndLoad)
  764. {
  765. cacheeligible = false;
  766. }
  767. StringBuffer xmlparams;
  768. StringBuffer normalizedSQL(parsedSQL->getNormalizedSQL());
  769. normalizedSQL.append(" | --TC=").append(cluster);
  770. if (username.length() > 0)
  771. normalizedSQL.append("--USER=").append(username.str());
  772. if (resultLimit > 0)
  773. normalizedSQL.append("--HARDLIMIT=").append(resultLimit);
  774. const char * wuusername = req.getUserName();
  775. if (wuusername && *wuusername)
  776. normalizedSQL.append("--WUOWN=").append(wuusername);
  777. if (hashoptions.length()>0)
  778. normalizedSQL.append("--HO=").append(hashoptions.str());
  779. if (compiledwuid.length() != 0)
  780. normalizedSQL.append("--PWUID=").append(compiledwuid.str());
  781. ESPLOG(LogMax, "WsSQL: getWorkUnitFactory...");
  782. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  783. ESPLOG(LogMax, "WsSQL: checking query cache...");
  784. if(cacheeligible && getCachedQuery(normalizedSQL.str(), compiledwuid.s))
  785. {
  786. ESPLOG(LogMax, "WsSQL: cache hit opening wuid %s...", compiledwuid.str());
  787. Owned<IConstWorkUnit> cw = factory->openWorkUnit(compiledwuid.str(), false);
  788. if (!cw)//cache hit but unavailable WU
  789. {
  790. ESPLOG(LogMax, "WsSQL: cache hit but unavailable WU...");
  791. removeQueryFromCache(normalizedSQL.str());
  792. compiledwuid.clear();
  793. }
  794. else
  795. clonable = true;
  796. }
  797. if (compiledwuid.length()==0)
  798. {
  799. {
  800. validateTargetName(cluster);
  801. if (querytype == SQLTypeCreateAndLoad)
  802. clonable = false;
  803. context.addTraceSummaryTimeStamp(LogNormal, "StartECLGenerate");
  804. ECLEngine::generateECL(parsedSQL, ecltext);
  805. if (hashoptions.length() > 0)
  806. ecltext.insert(0, hashoptions.str());
  807. context.addTraceSummaryTimeStamp(LogNormal, "EndECLGenerate");
  808. if (isEmpty(ecltext))
  809. throw MakeStringException(1,"Could not generate ECL from SQL.");
  810. ecltext.appendf(EMBEDDEDSQLQUERYCOMMENT, sqltext.str(), normalizedSQL.str());
  811. #if defined _DEBUG
  812. fprintf(stderr, "GENERATED ECL:\n%s\n", ecltext.str());
  813. #endif
  814. ESPLOG(LogMax, "WsSQL: creating new WU...");
  815. NewWsWorkunit wu(context);
  816. compiledwuid.set(wu->queryWuid());
  817. wu->setJobName("WsSQL Job");
  818. wu.setQueryText(ecltext.str());
  819. wu->setClusterName(cluster);
  820. if (clonable)
  821. wu->setCloneable(true);
  822. wu->setAction(WUActionCompile);
  823. if (resultLimit)
  824. wu->setResultLimit(resultLimit);
  825. if (wuusername && *wuusername)
  826. wu->setUser(wuusername);
  827. wu->commit();
  828. wu.clear();
  829. context.addTraceSummaryTimeStamp(LogNormal, "strtWUCompile");
  830. WsWuHelpers::submitWsWorkunit(context, compiledwuid.str(), cluster, nullptr, 0, 0, true, false, false, nullptr, nullptr, nullptr, nullptr);
  831. waitForWorkUnitToCompile(compiledwuid.str(), req.getWait());
  832. context.addTraceSummaryTimeStamp(LogNormal, "endWUCompile");
  833. }
  834. }
  835. ESPLOG(LogMax, "WsSQL: opening WU...");
  836. Owned<IConstWorkUnit> cw = factory->openWorkUnit(compiledwuid.str(), false);
  837. if (!cw)
  838. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT,"Cannot open workunit %s.", compiledwuid.str());
  839. WsWUExceptions errors(*cw);
  840. if (errors.ErrCount()>0)
  841. {
  842. WsWuInfo winfo(context, compiledwuid.str());
  843. winfo.getCommon(resp.updateWorkunit(), WUINFO_All);
  844. winfo.getExceptions(resp.updateWorkunit(), WUINFO_All);
  845. }
  846. else
  847. {
  848. if (querytype == SQLTypeCall)
  849. createWUXMLParams(xmlparams, parsedSQL, NULL, cw);
  850. else if (querytype == SQLTypeSelect)
  851. {
  852. if (!isEmptyString(cluster))
  853. validateTargetName(cluster);
  854. createWUXMLParams(xmlparams, parsedSQL->getParamList());
  855. }
  856. StringBuffer runningwuid;
  857. if (clonable)
  858. {
  859. context.addTraceSummaryTimeStamp(LogNormal, "StartWUCloneExe");
  860. cloneAndExecuteWU(context, compiledwuid.str(), runningwuid, xmlparams.str(), NULL, NULL, cluster);
  861. context.addTraceSummaryTimeStamp(LogNormal, "EndWUCloneExe");
  862. if(cacheeligible && !isQueryCached(normalizedSQL.str()))
  863. addQueryToCache(normalizedSQL.str(), compiledwuid.str());
  864. }
  865. else
  866. {
  867. context.addTraceSummaryTimeStamp(LogNormal, "StartWUSubmit");
  868. WsWuHelpers::submitWsWorkunit(context, compiledwuid.str(), cluster, nullptr, 0, 0, false, true, true, nullptr, nullptr, nullptr, nullptr);
  869. context.addTraceSummaryTimeStamp(LogNormal, "EndWUSubmit");
  870. runningwuid.set(compiledwuid.str());
  871. if (cacheeligible)
  872. addQueryToCache(normalizedSQL.str(), runningwuid.str());
  873. }
  874. int timeToWait = req.getWait();
  875. if (timeToWait != 0)
  876. {
  877. context.addTraceSummaryTimeStamp(LogNormal, "StartWUProcessWait");
  878. waitForWorkUnitToComplete(runningwuid.str(), timeToWait);
  879. context.addTraceSummaryTimeStamp(LogNormal, "EndWUProcessWait");
  880. }
  881. if (strcmp(runningwuid.str(), compiledwuid.str())!=0)
  882. resp.setParentWuId(compiledwuid.str());
  883. resp.setResultLimit(resultLimit);
  884. resp.setResultWindowCount( (unsigned)resultWindowCount);
  885. resp.setResultWindowStart( (unsigned)resultWindowStart);
  886. if (!req.getSuppressResults())
  887. {
  888. StringBuffer result;
  889. if (getWUResult(context, runningwuid.str(), result, (unsigned)resultWindowStart, (unsigned)resultWindowCount, 0, WSSQLRESULT, req.getSuppressXmlSchema() ? NULL : WSSQLRESULTSCHEMA))
  890. {
  891. StringBuffer count;
  892. if (getWUResult( context, runningwuid.str(), count , 0, 1, 1, WSSQLCOUNT, NULL))
  893. result.append(count.str());
  894. resp.setResult(result.str());
  895. }
  896. }
  897. WsWuInfo winfo(context, runningwuid);
  898. winfo.getCommon(resp.updateWorkunit(), WUINFO_All);
  899. winfo.getExceptions(resp.updateWorkunit(), WUINFO_All);
  900. }
  901. AuditSystemAccess(context.queryUserId(), true, "Updated %s", compiledwuid.str());
  902. }
  903. catch(IException* e)
  904. {
  905. FORWARDEXCEPTION(context, e, -1);
  906. }
  907. //catch (...)
  908. //{
  909. // me->append(*MakeStringException(0,"Unknown exception submitting %s",wuid.str()));
  910. //}
  911. context.addTraceSummaryTimeStamp(LogMin, "EndOnExecuteSQL");
  912. return true;
  913. }
  914. void CwssqlEx::createWUXMLParams(StringBuffer & xmlparams, const IArrayOf <ISQLExpression> * parameterlist)
  915. {
  916. xmlparams.append("<root>");
  917. for (int expindex = 0; expindex < parameterlist->length(); expindex++)
  918. {
  919. ISQLExpression * exp = &parameterlist->item(expindex);
  920. if (exp->getExpType() == Value_ExpressionType)
  921. {
  922. SQLValueExpression * currentvalplaceholder = static_cast<SQLValueExpression *>(exp);
  923. currentvalplaceholder->trimTextQuotes();
  924. xmlparams.appendf("<%s>", currentvalplaceholder->getPlaceHolderName());
  925. encodeXML(currentvalplaceholder->getValue(), xmlparams);
  926. xmlparams.appendf("</%s>", currentvalplaceholder->getPlaceHolderName());
  927. }
  928. else
  929. ESPLOG(LogNormal, "WsSQL: attempted to create XML params from unexpected expression type.");
  930. }
  931. xmlparams.append("</root>");
  932. DBGLOG("XML PARAMS: %s", xmlparams.str());
  933. }
  934. //Integrates all "variables" into "param" based xml
  935. void CwssqlEx::createWUXMLParams(StringBuffer & xmlparams, HPCCSQLTreeWalker* parsedSQL, IArrayOf<IConstNamedValue> *variables, IConstWorkUnit * cw)
  936. {
  937. IArrayOf<IConstWUResult> expectedparams;
  938. if (cw)
  939. {
  940. IConstWUResultIterator &vars = cw->getVariables();
  941. ForEach(vars)
  942. {
  943. IConstWUResult &cur = vars.query();
  944. expectedparams.append(cur);
  945. }
  946. }
  947. if (expectedparams.length() > 0)
  948. {
  949. int totalvars = 0;
  950. if (variables)
  951. totalvars = variables->length();
  952. if (parsedSQL && parsedSQL->getSqlType() == SQLTypeCall)
  953. {
  954. IArrayOf<ISQLExpression> * embeddedparams = NULL;
  955. if (parsedSQL)
  956. embeddedparams = parsedSQL->getStoredProcParamList();
  957. int parametersidx = 0;
  958. int varsidx = 0;
  959. SCMStringBuffer varname;
  960. if (embeddedparams && embeddedparams->length()>0)
  961. {
  962. xmlparams.append("<root>");
  963. for(int i=0; i < embeddedparams->length() && i < expectedparams.length(); i++)
  964. {
  965. expectedparams.item(i).getResultName(varname);
  966. xmlparams.append("<").append(varname.s.str()).append(">");
  967. ISQLExpression* paramcol = &embeddedparams->item(i);
  968. if (paramcol->getExpType() == ParameterPlaceHolder_ExpressionType)
  969. {
  970. if (varsidx < totalvars)
  971. {
  972. IConstNamedValue &item = variables->item(varsidx++);
  973. const char *value = item.getValue();
  974. if(value && *value)
  975. encodeXML(value, xmlparams);
  976. // else ??
  977. }
  978. }
  979. else
  980. {
  981. paramcol->toString(xmlparams,false);
  982. }
  983. xmlparams.append("</").append(varname.s.str()).append(">");
  984. }
  985. xmlparams.append("</root>");
  986. }
  987. }
  988. else
  989. {
  990. int parametersidx = 0;
  991. int varsidx = 0;
  992. SCMStringBuffer varname;
  993. xmlparams.append("<root>");
  994. for(int i=0; i < expectedparams.length() && i < totalvars; i++)
  995. {
  996. expectedparams.item(i).getResultName(varname);
  997. xmlparams.append("<").append(varname.s.str()).append(">");
  998. IConstNamedValue &item = variables->item(i);
  999. char * value = ((char *)item.getValue());
  1000. if (value && *value)
  1001. {
  1002. while(value && isspace(*value)) //fast trim left
  1003. value++;
  1004. int len = strlen(value);
  1005. while(len && isspace(value[len-1]))
  1006. len--;
  1007. value[len] = '\0';//fast trim right, even if len didn't change
  1008. if (len >= 2)
  1009. {
  1010. //WU cloning mechanism doesn't handle quoted strings very well...
  1011. //We're forced to blindly remove them here...
  1012. if (value[0] == '\'' && value[len-1] == '\'')
  1013. {
  1014. value[len-1] = '\0'; //clip rightmost quote
  1015. value++; //clip leftmost quote
  1016. }
  1017. }
  1018. if(len)
  1019. encodeXML(value, xmlparams);
  1020. // else ??
  1021. }
  1022. xmlparams.append("</").append(varname.s.str()).append(">");
  1023. }
  1024. xmlparams.append("</root>");
  1025. }
  1026. }
  1027. }
  1028. bool CwssqlEx::onExecutePreparedSQL(IEspContext &context, IEspExecutePreparedSQLRequest &req, IEspExecutePreparedSQLResponse &resp)
  1029. {
  1030. try
  1031. {
  1032. context.ensureFeatureAccess(WSSQLACCESS, SecAccess_Write, -1, "WsSQL::ExecutePreparedSQL: Permission denied.");
  1033. const char *cluster = req.getTargetCluster();
  1034. if (!isEmptyString(cluster))
  1035. validateTargetName(cluster);
  1036. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1037. StringBuffer runningWuId;
  1038. const char* parentWuId = req.getWuId();
  1039. Owned<IConstWorkUnit> cw = factory->openWorkUnit(parentWuId, false);
  1040. if (!cw)
  1041. throw MakeStringException(-1,"Cannot open workunit %s.", parentWuId);
  1042. WsWUExceptions errors(*cw);
  1043. if (errors.ErrCount()>0)
  1044. {
  1045. WsWuInfo winfo(context, parentWuId);
  1046. winfo.getCommon(resp.updateWorkunit(), WUINFO_All);
  1047. winfo.getExceptions(resp.updateWorkunit(), WUINFO_All);
  1048. }
  1049. else
  1050. {
  1051. StringBuffer xmlparams;
  1052. createWUXMLParams(xmlparams, NULL, &req.getVariables(),cw);
  1053. if (parentWuId && *parentWuId)
  1054. {
  1055. cloneAndExecuteWU(context, parentWuId, runningWuId, xmlparams, NULL, NULL, cluster);
  1056. }
  1057. else
  1058. throw MakeStringException(ECLWATCH_MISSING_PARAMS,"Missing WuId");
  1059. int timeToWait = req.getWait();
  1060. if (timeToWait != 0)
  1061. waitForWorkUnitToComplete(runningWuId.str(), timeToWait);
  1062. Owned<IConstWorkUnit> cw = factory->openWorkUnit(runningWuId.str(), false);
  1063. if (!cw)
  1064. throw MakeStringException(-1,"Cannot open workunit %s.", runningWuId.str());
  1065. resp.setParentWuId(parentWuId);
  1066. __int64 resultWindowStart = req.getResultWindowStart();
  1067. __int64 resultWindowCount = req.getResultWindowCount();
  1068. if (resultWindowStart < 0 || resultWindowCount <0 )
  1069. throw MakeStringException(-1,"Invalid result window value");
  1070. if (!req.getSuppressResults())
  1071. {
  1072. StringBuffer result;
  1073. if (getWUResult(context, runningWuId.str(), result, (unsigned)resultWindowStart, (unsigned)resultWindowCount, 0, WSSQLRESULT, req.getSuppressXmlSchema() ? NULL : WSSQLRESULTSCHEMA))
  1074. resp.setResult(result.str());
  1075. }
  1076. WsWuInfo winfo(context, runningWuId);
  1077. winfo.getCommon(resp.updateWorkunit(), WUINFO_All);
  1078. winfo.getExceptions(resp.updateWorkunit(), WUINFO_All);
  1079. winfo.getVariables(resp.updateWorkunit(), WUINFO_All);
  1080. }
  1081. }
  1082. catch(IException* e)
  1083. {
  1084. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1085. }
  1086. return true;
  1087. }
  1088. bool CwssqlEx::isQueryCached(const char * sqlQuery)
  1089. {
  1090. CriticalBlock block(critCache);
  1091. return (sqlQuery && cachedSQLQueries.find(sqlQuery) != cachedSQLQueries.end());
  1092. }
  1093. bool CwssqlEx::getCachedQuery(const char * sqlQuery, StringBuffer & wuid)
  1094. {
  1095. CriticalBlock block(critCache);
  1096. if(sqlQuery && cachedSQLQueries.find(sqlQuery) != cachedSQLQueries.end())
  1097. {
  1098. wuid.set(cachedSQLQueries.find(sqlQuery)->second.c_str());
  1099. return true;
  1100. }
  1101. return false;
  1102. }
  1103. void CwssqlEx::removeQueryFromCache(const char * sqlQuery)
  1104. {
  1105. CriticalBlock block(critCache);
  1106. cachedSQLQueries.erase(sqlQuery);
  1107. }
  1108. bool CwssqlEx::addQueryToCache(const char * sqlQuery, const char * wuid)
  1109. {
  1110. if (sqlQuery && *sqlQuery && wuid && *wuid)
  1111. {
  1112. CriticalBlock block(critCache);
  1113. if (isCacheExpired())
  1114. {
  1115. ESPLOG(LogNormal, "WsSQL: Query Cache has expired and is being flushed.");
  1116. //Flushing cache logic could have been in dedicated function, but
  1117. //putting it here makes this action more atomic, less synchronization concerns
  1118. cachedSQLQueries.clear();
  1119. setNewCacheFlushTime();
  1120. }
  1121. cachedSQLQueries.insert(std::pair<std::string,std::string>(sqlQuery, wuid));
  1122. }
  1123. return false;
  1124. }
  1125. bool CwssqlEx::onPrepareSQL(IEspContext &context, IEspPrepareSQLRequest &req, IEspPrepareSQLResponse &resp)
  1126. {
  1127. bool success = false;
  1128. StringBuffer sqltext;
  1129. StringBuffer ecltext;
  1130. bool clonable = false;
  1131. try
  1132. {
  1133. context.ensureFeatureAccess(WSSQLACCESS, SecAccess_Write, -1, "WsSQL::PrepareSQL: Permission denied.");
  1134. double version = context.getClientVersion();
  1135. StringBuffer username;
  1136. context.getUserID(username);
  1137. const char* passwd = context.queryPassword();
  1138. sqltext.set(req.getSqlText());
  1139. if (sqltext.length() <= 0)
  1140. throw MakeStringException(1,"Empty SQL request.");
  1141. Owned<HPCCSQLTreeWalker> parsedSQL;
  1142. parsedSQL.setown(parseSQL(context, sqltext, false));
  1143. if (parsedSQL->getSqlType() == SQLTypeCall)
  1144. {
  1145. if (strlen(parsedSQL->getQuerySetName())==0)
  1146. {
  1147. if (strlen(req.getTargetQuerySet())==0)
  1148. throw MakeStringException(-1,"Missing Target QuerySet.");
  1149. else
  1150. parsedSQL->setQuerySetName(req.getTargetQuerySet());
  1151. }
  1152. }
  1153. const char * cluster = req.getTargetCluster();
  1154. StringBuffer hashoptions;
  1155. if (version > 3.03)
  1156. {
  1157. StringArray & alternates = req.getAlternateClusters();
  1158. if (alternates.length() > 0)
  1159. processMultipleClusterOption(alternates, cluster, hashoptions);
  1160. }
  1161. StringBuffer xmlparams;
  1162. StringBuffer normalizedSQL(parsedSQL->getNormalizedSQL());
  1163. normalizedSQL.append(" | --TC=").append(cluster);
  1164. if (username.length() > 0)
  1165. normalizedSQL.append("--USER=").append(username.str());
  1166. if (hashoptions.length()>0)
  1167. normalizedSQL.append("--HO=").append(hashoptions.str());
  1168. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1169. SCMStringBuffer wuid;
  1170. if(getCachedQuery(normalizedSQL.str(), wuid.s))
  1171. {
  1172. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid.str(), false);
  1173. if (!cw)//cache hit but unavailable WU
  1174. {
  1175. removeQueryFromCache(normalizedSQL.str());
  1176. wuid.clear();
  1177. }
  1178. }
  1179. if(wuid.length()==0)
  1180. {
  1181. if (parsedSQL->getSqlType() == SQLTypeCall)
  1182. {
  1183. WsEclWuInfo wsinfo("", parsedSQL->getQuerySetName(), parsedSQL->getStoredProcName(), username.str(), passwd);
  1184. wuid.set(wsinfo.ensureWuid());
  1185. //if call somePublishedQuery(1,2,3);
  1186. // or
  1187. // someotherPublishedQuery(1,?)
  1188. //must clone published query wuid and set params
  1189. //else just return published query WUID
  1190. if (parsedSQL->getStoredProcParamListCount() > 0 && !parsedSQL->isParameterizedCall() )
  1191. throw MakeStringException(-1, "Prepared Call query must be fully parameterized");
  1192. //KEEP THIS AROUND IF WE WANT TO SUPPORT CLONING WU with embedded params
  1193. // if (parsedSQL->isParameterizedCall())
  1194. // {
  1195. // createXMLParams(xmlparams, parsedSQL, NULL, wsinfo.wu);
  1196. //
  1197. // SCMStringBuffer newwuid;
  1198. // NewWsWorkunit wu(context);
  1199. // wu->getWuid(newwuid);
  1200. // if (xmlparams && *xmlparams)
  1201. // wu->setXmlParams(xmlparams);
  1202. //
  1203. // WsWuProcess::copyWsWorkunit(context, *wu, wuid.s.str());
  1204. //
  1205. // //StringBuffer params;
  1206. // //toXML(wu->getXmlParams(), params, true, true);
  1207. // wu->setCloneable(true);
  1208. // wu->setAction(WUActionCompile);
  1209. //
  1210. // wu->commit();
  1211. // wu.clear();
  1212. //
  1213. // WsWuProcess::submitWsWorkunit(context, newwuid.str(), req.getTargetCluster(), NULL, 0, 0, true, false, false, xmlparams.str(), NULL, NULL);
  1214. // waitForWorkUnitToCompile(newwuid.str(), req.getWait());
  1215. //
  1216. // wuid.s.set(newwuid.str());
  1217. // }
  1218. }
  1219. else
  1220. {
  1221. validateTargetName(cluster);
  1222. ECLEngine::generateECL(parsedSQL, ecltext);
  1223. if (hashoptions.length() > 0)
  1224. ecltext.insert(0, hashoptions.str());
  1225. #if defined _DEBUG
  1226. fprintf(stderr, "GENERATED ECL:\n%s\n", ecltext.str());
  1227. #endif
  1228. if (isEmpty(ecltext))
  1229. throw MakeStringException(1,"Could not generate ECL from SQL.");
  1230. //ecltext.appendf("\n\n/****************************************************\nOriginal SQL: \"%s\"\nNormalized SQL: \"%s\"\n****************************************************/\n", sqltext.str(), normalizedSQL.str());
  1231. ecltext.appendf(EMBEDDEDSQLQUERYCOMMENT, sqltext.str(), normalizedSQL.str());
  1232. NewWsWorkunit wu(context);
  1233. wuid.set(wu->queryWuid());
  1234. wu->setClusterName(cluster);
  1235. wu->setCloneable(true);
  1236. wu->setAction(WUActionCompile);
  1237. wu.setQueryText(ecltext.str());
  1238. wu->setJobName("WsSQL PreparedQuery Job");
  1239. StringBuffer xmlparams;
  1240. createWUXMLParams(xmlparams, parsedSQL, NULL, NULL);
  1241. wu->commit();
  1242. wu.clear();
  1243. WsWuHelpers::submitWsWorkunit(context, wuid.str(), cluster, nullptr, 0, 0, true, false, false, xmlparams.str(), nullptr, nullptr, nullptr);
  1244. success = waitForWorkUnitToCompile(wuid.str(), req.getWait());
  1245. }
  1246. if (success)
  1247. addQueryToCache(normalizedSQL.str(), wuid.s.str());
  1248. }
  1249. WsWuInfo winfo(context, wuid.str());
  1250. winfo.getCommon(resp.updateWorkunit(), WUINFO_All);
  1251. winfo.getExceptions(resp.updateWorkunit(), WUINFO_All);
  1252. StringBuffer result;
  1253. getWUResult(context, wuid.str(), result, 0, 0, 0, WSSQLRESULT, WSSQLRESULTSCHEMA);
  1254. resp.setResult(result);
  1255. AuditSystemAccess(context.queryUserId(), true, "Updated %s", wuid.str());
  1256. }
  1257. catch(IException* e)
  1258. {
  1259. FORWARDEXCEPTION(context, e, -1);
  1260. }
  1261. return true;
  1262. }
  1263. bool CwssqlEx::executePublishedQueryByName(IEspContext &context, const char * queryset, const char * queryname, StringBuffer &clonedwuid, const char *paramXml, IArrayOf<IConstNamedValue> *variables, const char * targetcluster, int start, int count)
  1264. {
  1265. bool success = true;
  1266. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1267. if (factory.get())
  1268. {
  1269. StringBuffer wuid;
  1270. StringBuffer username;
  1271. context.getUserID(username);
  1272. const char* passwd = context.queryPassword();
  1273. WsEclWuInfo wsinfo(wuid, queryset, queryname, username.str(), passwd);
  1274. success = executePublishedQueryByWuId(context, wsinfo.ensureWuid(), clonedwuid, paramXml, variables, targetcluster, start, count);
  1275. }
  1276. else
  1277. success = false;
  1278. return success;
  1279. }
  1280. bool CwssqlEx::executePublishedQueryByWuId(IEspContext &context, const char * targetwuid, StringBuffer &clonedwuid, const char *paramXml, IArrayOf<IConstNamedValue> *variables, const char * targetcluster, int start, int count)
  1281. {
  1282. bool success = true;
  1283. if (targetwuid && *targetwuid)
  1284. {
  1285. success = cloneAndExecuteWU(context, targetwuid, clonedwuid, paramXml, variables, NULL, targetcluster);
  1286. /*
  1287. if (waittime != 0)
  1288. waitForWorkUnitToComplete(clonedwui.str(), waittime);
  1289. Owned<IConstWorkUnit> cw = factory->openWorkUnit(clonedwui.str(), false);
  1290. if (!cw)
  1291. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT,"Cannot open workunit %s.", clonedwui.str());
  1292. getWUResult(context, clonedwui.str(), resp, start, count);
  1293. */
  1294. }
  1295. else
  1296. success = false;
  1297. return success;
  1298. }
  1299. bool CwssqlEx::executePublishedQuery(IEspContext &context, const char * queryset, const char * queryname, StringBuffer &resp, int start, int count, int waittime)
  1300. {
  1301. bool success = true;
  1302. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1303. if (factory.get())
  1304. {
  1305. StringBuffer wuid;
  1306. StringBuffer username;
  1307. context.getUserID(username);
  1308. const char* passwd = context.queryPassword();
  1309. WsEclWuInfo wsinfo(wuid, queryset, queryname, username.str(), passwd);
  1310. StringBuffer clonedwui;
  1311. cloneAndExecuteWU(context, wsinfo.ensureWuid(), clonedwui, NULL, NULL, NULL, "");
  1312. if (waittime != 0)
  1313. waitForWorkUnitToComplete(clonedwui.str(), waittime);
  1314. Owned<IConstWorkUnit> cw = factory->openWorkUnit(clonedwui.str(), false);
  1315. if (!cw)
  1316. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT,"Cannot open workunit %s.", clonedwui.str());
  1317. getWUResult(context, clonedwui.str(), resp, start, count, 0, WSSQLRESULT, WSSQLRESULTSCHEMA);
  1318. }
  1319. else
  1320. success = false;
  1321. return success;
  1322. }
  1323. bool CwssqlEx::executePublishedQuery(IEspContext &context, const char * wuid, StringBuffer &resp, int start, int count, int waittime)
  1324. {
  1325. bool success = true;
  1326. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1327. if (factory.get())
  1328. {
  1329. StringBuffer username;
  1330. context.getUserID(username);
  1331. const char* passwd = context.queryPassword();
  1332. WsEclWuInfo wsinfo(wuid, "", "", username.str(), passwd);
  1333. StringBuffer clonedwui;
  1334. cloneAndExecuteWU(context, wsinfo.ensureWuid(), clonedwui, NULL, NULL, NULL, "");
  1335. if (waittime != 0)
  1336. waitForWorkUnitToComplete(clonedwui.str(), waittime);
  1337. Owned<IConstWorkUnit> cw = factory->openWorkUnit(clonedwui.str(), false);
  1338. if (!cw)
  1339. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT,"Cannot open workunit %s.", clonedwui.str());
  1340. getWUResult(context, clonedwui.str(), resp, start, count, 0, WSSQLRESULT, WSSQLRESULTSCHEMA);
  1341. }
  1342. else
  1343. success = false;
  1344. return success;
  1345. }
  1346. bool CwssqlEx::cloneAndExecuteWU(IEspContext &context, const char * originalwuid, StringBuffer &clonedwuid, const char *paramXml, IArrayOf<IConstNamedValue> *variables, IArrayOf<IConstNamedValue> *debugs, const char * targetcluster)
  1347. {
  1348. bool success = true;
  1349. try
  1350. {
  1351. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1352. if (originalwuid && *originalwuid)
  1353. {
  1354. if (!looksLikeAWuid(originalwuid, 'W'))
  1355. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid Workunit ID: %s", originalwuid);
  1356. Owned<IConstWorkUnit> pwu = factory->openWorkUnit(originalwuid, false);
  1357. if (!pwu)
  1358. throw MakeStringException(-1,"Cannot open workunit %s.", originalwuid);
  1359. if (pwu->getExceptionCount()>0)
  1360. {
  1361. WsWUExceptions errors(*pwu);
  1362. if (errors.ErrCount()>0)
  1363. throw MakeStringException(-1,"Original query contains errors %s.", originalwuid);
  1364. }
  1365. StringBufferAdaptor isvWuid(clonedwuid);
  1366. WsWuHelpers::runWsWorkunit(
  1367. context,
  1368. clonedwuid,
  1369. originalwuid,
  1370. targetcluster,
  1371. paramXml,
  1372. variables,
  1373. debugs);
  1374. }
  1375. else
  1376. throw MakeStringException(ECLWATCH_MISSING_PARAMS,"Missing WuId");
  1377. }
  1378. catch(IException* e)
  1379. {
  1380. FORWARDEXCEPTION(context, e, -1);
  1381. }
  1382. return success;
  1383. }
  1384. bool CwssqlEx::onCreateTableAndLoad(IEspContext &context, IEspCreateTableAndLoadRequest &req, IEspCreateTableAndLoadResponse &resp)
  1385. {
  1386. context.ensureFeatureAccess(WSSQLACCESS, SecAccess_Write, -1, "WsSQL::CreateTableAndLoad: Permission denied.");
  1387. bool success = true;
  1388. const char * targetTableName = req.getTableName();
  1389. if (!targetTableName || !*targetTableName)
  1390. throw MakeStringException(-1, "WsSQL::CreateTableAndLoad: Error: TableName cannot be empty.");
  1391. if (!HPCCFile::validateFileName(targetTableName))
  1392. throw MakeStringException(-1, "WsSQL::CreateTableAndLoad: Error: Target TableName is invalid: %s.", targetTableName);
  1393. const char * cluster = req.getTargetCluster();
  1394. if (!isEmptyString(cluster))
  1395. validateTargetName(cluster);
  1396. IConstDataSourceInfo & datasource = req.getDataSource();
  1397. StringBuffer sourceDataFileName;
  1398. sourceDataFileName.set(datasource.getSprayedFileName()).trim();
  1399. if (sourceDataFileName.length() == 0)
  1400. {
  1401. sourceDataFileName.set(datasource.getLandingZoneFileName());
  1402. if (sourceDataFileName.length() == 0)
  1403. throw MakeStringException(-1, "WsSQL::CreateTableAndLoad: Error: Data Source File Name cannot be empty, provide either sprayed file name, or landing zone file name.");
  1404. const char * lzIP = datasource.getLandingZoneIP();
  1405. if (!lzIP || !*lzIP)
  1406. throw MakeStringException(-1, "WsSQL::CreateTableAndLoad: Error: LandingZone IP cannot be empty if targeting a landing zone file.");
  1407. StringBuffer lzPath(datasource.getLandingZonePath());
  1408. if (!lzPath.length())
  1409. throw MakeStringException(-1, "WsSQL::CreateTableAndLoad: Error: Landingzone path cannot be empty.");
  1410. addPathSepChar(lzPath);
  1411. RemoteFilename rfn;
  1412. SocketEndpoint ep(lzIP);
  1413. rfn.setPath(ep, lzPath.append(sourceDataFileName.str()).str());
  1414. CDfsLogicalFileName dlfn;
  1415. dlfn.setExternal(rfn);
  1416. dlfn.get(sourceDataFileName.clear(), false, false);
  1417. }
  1418. IConstDataType & format = req.getDataSourceType();
  1419. const char * formatname = "";
  1420. CHPCCFileType formattype = format.getType();
  1421. switch (formattype)
  1422. {
  1423. case CHPCCFileType_FLAT:
  1424. formatname = "FLAT";
  1425. break;
  1426. case CHPCCFileType_CSV:
  1427. formatname = "CSV";
  1428. break;
  1429. case CHPCCFileType_JSON:
  1430. formatname = "JSON";
  1431. break;
  1432. case CHPCCFileType_XML:
  1433. formatname = "XML";
  1434. break;
  1435. default:
  1436. throw MakeStringException(-1, "WsSQL::CreateTableAndLoad: Error: Invalid file format detected.");
  1437. }
  1438. StringBuffer ecl;
  1439. StringBuffer recDef;
  1440. ecl.set("import std;\n");
  1441. {
  1442. IArrayOf<IConstEclFieldDeclaration>& eclFields = req.getEclFields();
  1443. if (eclFields.length() == 0)
  1444. throw MakeStringException(-1, "WsSQL::CreateTableAndLoad: Error: Empty record definition detected.");
  1445. recDef.set("TABLERECORDDEF := RECORD\n");
  1446. ForEachItemIn(fieldindex, eclFields)
  1447. {
  1448. IConstEclFieldDeclaration &eclfield = eclFields.item(fieldindex);
  1449. IConstEclFieldType &ecltype = eclfield.getEclFieldType();
  1450. const char * name = "";
  1451. CHPCCFieldType format = ecltype.getType();
  1452. switch (format)
  1453. {
  1454. case CHPCCFieldType_BOOLEAN:
  1455. name = "BOOLEAN";
  1456. break;
  1457. case CHPCCFieldType_INTEGER:
  1458. name = "INTEGER";
  1459. break;
  1460. case CHPCCFieldType_xUNSIGNED:
  1461. name = "UNSIGNED";
  1462. break;
  1463. case CHPCCFieldType_REAL:
  1464. name = "REAL";
  1465. break;
  1466. case CHPCCFieldType_DECIMAL:
  1467. name = "DECIMAL";
  1468. break;
  1469. case CHPCCFieldType_xSTRING:
  1470. name = "STRING";
  1471. break;
  1472. case CHPCCFieldType_QSTRING:
  1473. name = "QSTRING";
  1474. break;
  1475. case CHPCCFieldType_UNICODE:
  1476. name = "UNICODE";
  1477. break;
  1478. case CHPCCFieldType_DATA:
  1479. name = "DATA";
  1480. break;
  1481. case CHPCCFieldType_VARSTRING:
  1482. name = "VARSTRING";
  1483. break;
  1484. case CHPCCFieldType_VARUNICODE:
  1485. name = "VARUNICODE";
  1486. break;
  1487. default:
  1488. throw MakeStringException(-1, "WsSQL::CreateTableAndLoad: Error: Unrecognized field type detected.");
  1489. }
  1490. int len = ecltype.getLength();
  1491. const char * locale = ecltype.getLocale();
  1492. int precision = ecltype.getPrecision();
  1493. recDef.appendf("\t%s", name);
  1494. if (len > 0)
  1495. {
  1496. if(isdigit(recDef.charAt(recDef.length() - 1)))
  1497. recDef.append("_");
  1498. recDef.append(len);
  1499. }
  1500. if (locale && *locale)
  1501. recDef.append(locale);
  1502. if (precision > 0)
  1503. recDef.appendf("_%d", precision);
  1504. recDef.appendf(" %s;\n", eclfield.getFieldName());
  1505. }
  1506. recDef.append("END;\n");
  1507. }
  1508. ecl.append(recDef.str());
  1509. bool overwrite = req.getOverwrite();
  1510. StringBuffer formatnamefull(formatname);
  1511. IArrayOf<IConstDataTypeParam> & formatparams = format.getParams();
  1512. int formatparamscount = formatparams.length();
  1513. if (formatparamscount > 0 )
  1514. {
  1515. formatnamefull.append("(");
  1516. for (int paramindex = 0; paramindex < formatparamscount; paramindex++)
  1517. {
  1518. IConstDataTypeParam &paramitem = formatparams.item(paramindex);
  1519. const char * paramname = paramitem.getName();
  1520. if (!paramname || !*paramname)
  1521. throw MakeStringException(-1, "WsSQL::CreateTableAndLoad: Error: Format type '%s' appears to have unnamed parameter(s).", formatname);
  1522. StringArray & paramvalues = paramitem.getValues();
  1523. int paramvalueslen = paramvalues.length();
  1524. formatnamefull.appendf("%s(", paramname);
  1525. if (paramvalueslen > 1)
  1526. formatnamefull.append("[");
  1527. for (int paramvaluesindex = 0; paramvaluesindex < paramvalueslen; paramvaluesindex++)
  1528. {
  1529. formatnamefull.appendf("'%s'%s", paramvalues.item(paramvaluesindex), paramvaluesindex < paramvalueslen-1 ? "," : "");
  1530. }
  1531. if (paramvalueslen > 1)
  1532. formatnamefull.append("]");
  1533. formatnamefull.append(")");
  1534. if (paramindex < formatparamscount-1)
  1535. formatnamefull.append(",");
  1536. }
  1537. formatnamefull.append(")");
  1538. }
  1539. ecl.appendf("\nFILEDATASET := DATASET('~%s', TABLERECORDDEF, %s);\n",sourceDataFileName.str(), formatnamefull.str());
  1540. ecl.appendf("OUTPUT(FILEDATASET, ,'~%s'%s);", targetTableName, overwrite ? ", OVERWRITE" : "");
  1541. const char * description = req.getTableDescription();
  1542. if (description && * description)
  1543. ecl.appendf("\nStd.file.setfiledescription('~%s','%s')", targetTableName, description);
  1544. ESPLOG(LogMax, "WsSQL: creating new WU...");
  1545. NewWsWorkunit wu(context);
  1546. SCMStringBuffer compiledwuid;
  1547. compiledwuid.set(wu->queryWuid());
  1548. wu->setJobName("WsSQL Create table");
  1549. wu.setQueryText(ecl.str());
  1550. wu->setClusterName(cluster);
  1551. wu->setAction(WUActionCompile);
  1552. const char * wuusername = req.getOwner();
  1553. if (wuusername && *wuusername)
  1554. wu->setUser(wuusername);
  1555. wu->commit();
  1556. wu.clear();
  1557. ESPLOG(LogMax, "WsSQL: compiling WU...");
  1558. WsWuHelpers::submitWsWorkunit(context, compiledwuid.str(), cluster, nullptr, 0, 0, true, false, false, nullptr, nullptr, nullptr, nullptr);
  1559. waitForWorkUnitToCompile(compiledwuid.str(), req.getWait());
  1560. ESPLOG(LogMax, "WsSQL: finish compiling WU...");
  1561. ESPLOG(LogMax, "WsSQL: opening WU...");
  1562. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1563. Owned<IConstWorkUnit> cw = factory->openWorkUnit(compiledwuid.str(), false);
  1564. if (!cw)
  1565. throw MakeStringException(ECLWATCH_CANNOT_UPDATE_WORKUNIT,"Cannot open WorkUnit %s.", compiledwuid.str());
  1566. WsWUExceptions errors(*cw);
  1567. if (errors.ErrCount()>0)
  1568. {
  1569. WsWuInfo winfo(context, compiledwuid.str());
  1570. winfo.getExceptions(resp.updateWorkunit(), WUINFO_All);
  1571. success = false;
  1572. }
  1573. else
  1574. {
  1575. ESPLOG(LogMax, "WsSQL: executing WU(%s)...", compiledwuid.str());
  1576. WsWuHelpers::submitWsWorkunit(context, compiledwuid.str(), cluster, nullptr, 0, 0, false, true, true, nullptr, nullptr, nullptr, nullptr);
  1577. ESPLOG(LogMax, "WsSQL: waiting on WU(%s)...", compiledwuid.str());
  1578. waitForWorkUnitToComplete(compiledwuid.str(), req.getWait());
  1579. ESPLOG(LogMax, "WsSQL: finished waiting on WU(%s)...", compiledwuid.str());
  1580. Owned<IConstWorkUnit> rw = factory->openWorkUnit(compiledwuid.str(), false);
  1581. if (!rw)
  1582. throw MakeStringException(-1,"WsSQL: Cannot verify create and load request success.");
  1583. WsWuInfo winfo(context, compiledwuid.str());
  1584. WsWUExceptions errors(*rw);
  1585. if (errors.ErrCount() > 0 )
  1586. {
  1587. winfo.getExceptions(resp.updateWorkunit(), WUINFO_All);
  1588. success = false;
  1589. }
  1590. winfo.getCommon(resp.updateWorkunit(), WUINFO_All);
  1591. resp.setSuccess(success);
  1592. resp.setEclRecordDefinition(recDef.str());
  1593. resp.setTableName(targetTableName);
  1594. }
  1595. return success;
  1596. }
  1597. bool CwssqlEx::onGetResults(IEspContext &context, IEspGetResultsRequest &req, IEspGetResultsResponse &resp)
  1598. {
  1599. context.ensureFeatureAccess(WSSQLACCESS, SecAccess_Read, -1, "WsSQL::GetResults: Permission denied.");
  1600. bool success = true;
  1601. const char* parentWuId = req.getWuId();
  1602. if (parentWuId && *parentWuId)
  1603. {
  1604. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1605. if (factory.get())
  1606. {
  1607. Owned<IConstWorkUnit> cw = factory->openWorkUnit(parentWuId, false);
  1608. if (!cw)
  1609. throw MakeStringException(-1,"Cannot open workunit %s.", parentWuId);
  1610. __int64 resultWindowStart = req.getResultWindowStart();
  1611. __int64 resultWindowCount = req.getResultWindowCount();
  1612. if (resultWindowStart < 0 || resultWindowCount <0 )
  1613. throw MakeStringException(-1,"Invalid result window value");
  1614. //resp.setResultLimit(resultLimit);
  1615. resp.setResultWindowCount((unsigned)resultWindowCount);
  1616. resp.setResultWindowStart((unsigned)resultWindowStart);
  1617. StringBuffer result;
  1618. if (getWUResult(context, parentWuId, result, (unsigned)resultWindowStart, (unsigned)resultWindowCount, 0, WSSQLRESULT, req.getSuppressXmlSchema() ? NULL : WSSQLRESULTSCHEMA))
  1619. resp.setResult(result.str());
  1620. WsWuInfo winfo(context, parentWuId);
  1621. winfo.getCommon(resp.updateWorkunit(), WUINFO_All);
  1622. winfo.getExceptions(resp.updateWorkunit(), WUINFO_All);
  1623. }
  1624. else
  1625. throw MakeStringException(-1,"Could not create WU factory object");
  1626. }
  1627. else
  1628. throw MakeStringException(-1,"Missing WuId");
  1629. return success;
  1630. }
  1631. bool CwssqlEx::publishWorkunit(IEspContext &context, const char * queryname, const char * wuid, const char * targetcluster)
  1632. {
  1633. Owned<IWorkUnitFactory> factory = getWorkUnitFactory(context.querySecManager(), context.queryUser());
  1634. Owned<IConstWorkUnit> cw = factory->openWorkUnit(wuid, false);
  1635. if (!cw)
  1636. throw MakeStringException(ECLWATCH_CANNOT_OPEN_WORKUNIT,"Cannot find the workunit %s", wuid);
  1637. SCMStringBuffer queryName;
  1638. if (!isEmptyString(queryname))
  1639. queryName.set(queryname);
  1640. else
  1641. queryName.set(cw->queryJobName());
  1642. if (!queryName.length())
  1643. throw MakeStringException(ECLWATCH_MISSING_PARAMS, "Query/Job name not defined for publishing workunit %s", wuid);
  1644. SCMStringBuffer target;
  1645. if (!isEmptyString(targetcluster))
  1646. target.set(targetcluster);
  1647. else
  1648. target.set(cw->queryClusterName());
  1649. validateTargetName(target.str());
  1650. //RODRIGO this is needed:
  1651. //copyQueryFilesToCluster(context, cw, "", target.str(), queryName.str(), false);
  1652. WorkunitUpdate wu(&cw->lock());
  1653. wu->setJobName(queryName.str());
  1654. StringBuffer queryId;
  1655. addQueryToQuerySet(wu, target.str(), queryName.str(), MAKE_ACTIVATE, queryId, context.queryUserId());
  1656. wu->commit();
  1657. wu.clear();
  1658. return true;
  1659. }