irods  4.2.8
About: iRODS (the integrated Rule Oriented Data System) is a distributed data-management system for creating data grids, digital libraries, persistent archives, and real-time data systems.
  Fossies Dox: irods-4.2.8.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

general_query.cpp
Go to the documentation of this file.
1 
3 /*
4 
5  These routines are the genSql routines, which are used to convert the
6  generalQuery arguments into SQL select strings. The generalQuery
7  arguments are any arbitrary set of columns in the various tables, so
8  these routines have to generate SQL that can link any table.column to
9  any other.
10 
11  Also see the fklinks.c routine which calls fklink (below) to
12  initialize the table table.
13 
14  At the core, is an algorithm to find a spanning tree in our graph set
15  up by fklink. This does not need to find the minimal spanning tree,
16  just THE spanning tree, as there should be only one. Thus there are
17  no weights on the arcs of this tree either. But complicating this is
18  the fact that there are nodes that can create cycles in the
19  semi-tree, but these are flagged so the code can stop when
20  encountering these.
21 
22  There is also a routine that checks for cycles, tCycleChk, which can
23  be called when the tables change to make sure there are no cycles.
24 
25  */
26 #include "rodsClient.h"
28 #include "mid_level.hpp"
29 #include "low_level.hpp"
30 #include "irods_virtual_path.hpp"
31 
32 #include <boost/algorithm/string.hpp>
33 
34 #include <string>
35 #include <algorithm>
36 
37 extern int logSQLGenQuery;
38 
40 int insertWhere( char *condition, int option );
41 
42 /* use a column size of at least this many characters: */
43 #define MINIMUM_COL_SIZE 50
44 
45 #define MAX_LINKS_TABLES_OR_COLUMNS 500
46 
47 #define MAX_TSQL 110
48 
49 #define MAX_SQL_SIZE_GQ MAX_SQL_SIZE_GENERAL_QUERY // JMC - backport 4848
50 
51 int firstCall = 1;
52 
68 
69 
70 struct tlinks {
71  int table1;
72  int table2;
75 
76 int nLinks;
77 
78 struct tTables {
81  int cycler;
82  int flag;
83  char tableAbbrev[2];
85 
86 int nTables;
87 
88 struct tColumns {
93 
95 
96 int nToFind;
97 
99 
100 int debug = 0;
101 int debug2 = 0;
102 
103 namespace
104 {
105  int mask_query_argument(std::string& _condition, std::string::size_type _offset)
106  {
107  if (_condition.empty() || _offset >= _condition.size()) {
108  return -1;
109  }
110 
111  const auto bpos = _condition.find_first_of("'", _offset);
112 
113  if (bpos == std::string::npos) {
114  return -1;
115  }
116 
117  const auto epos = _condition.find_first_of("'", bpos + 1);
118 
119  if (epos == std::string::npos) {
120  return -1;
121  }
122 
123  std::fill(&_condition[bpos + 1], &_condition[epos], ' ');
124 
125  return epos + 1;
126  }
127 
128  void mask_query_arguments(std::string& _condition)
129  {
130  int offset = 0;
131  while ((offset = mask_query_argument(_condition, offset)) > -1);
132  }
133 } // anonymous namespace
134 
135 /*
136  Used by fklink (below) to find an existing name and return the
137  value. Once the table is set up, the code can use the integer
138  table1 and table2 values to more quickly compare.
139  */
140 int fkFindName( const char *tableName ) {
141  int i;
142  for ( i = 0; i < nTables; i++ ) {
143  if ( strcmp( Tables[i].tableName, tableName ) == 0 ) {
144  return i;
145  }
146  }
147  rodsLog( LOG_ERROR, "fkFindName table %s unknown", tableName );
148  return 0;
149 }
150 
151 /*
152 sFklink - Setup Foreign Key Link. This is called from the initization
153 routine with various parameters, to set up a table of links between DB
154 tables.
155  */
156 int
157 sFklink( const char *table1, const char *table2, const char *connectingSQL ) {
159  rodsLog( LOG_ERROR, "fklink table full %d", CAT_TOO_MANY_TABLES );
160  return CAT_TOO_MANY_TABLES;
161  }
162  Links[nLinks].table1 = fkFindName( table1 );
163  Links[nLinks].table2 = fkFindName( table2 );
164  snprintf( Links[nLinks].connectingSQL, sizeof( Links[nLinks].connectingSQL ), "%s", connectingSQL );
165  if ( debug > 1 ) printf( "link %d is from %d to %d\n", nLinks,
166  Links[nLinks].table1,
167  Links[nLinks].table2 );
168  if ( debug2 ) printf( "T%2.2d L%2.2d T%2.2d\n",
169  Links[nLinks].table1, nLinks,
170  Links[nLinks].table2 );
171  nLinks++;
172  return 0;
173 }
174 
175 /*
176 sTableInit - initialize the Tables, Links, and Columns tables.
177  */
178 int
180  nLinks = 0;
181  nTables = 0;
182  nColumns = 0;
183  memset( Links, 0, sizeof( Links ) );
184  memset( Tables, 0, sizeof( Tables ) );
185  memset( Columns, 0, sizeof( Columns ) );
186  return 0;
187 }
188 
189 /*
190  sTable setup tables.
191 
192  Set up a C table of DB Tables.
193  Similar to fklink, this is called with different values to initialize
194  a table used within this module.
195 
196  The "cycler" flag is 1 if this table could cause cycles. When a node
197  of this type is reached, the subtrees from there are not searched so
198  as to avoid loops.
199 
200 */
201 int
202 sTable( const char *tableName, const char *tableAlias, int cycler ) {
204  rodsLog( LOG_ERROR, "sTable table full %d", CAT_TOO_MANY_TABLES );
205  return CAT_TOO_MANY_TABLES;
206  }
207  snprintf( Tables[nTables].tableName, sizeof( Tables[nTables].tableName ), "%s", tableName );
208  snprintf( Tables[nTables].tableAlias, sizeof( Tables[nTables].tableAlias ), "%s", tableAlias );
209  Tables[nTables].cycler = cycler;
210  if ( debug > 1 ) {
211  printf( "table %d is %s\n", nTables, tableName );
212  }
213  nTables++;
214  return 0;
215 }
216 
217 int
218 sColumn( int defineVal, const char *tableName, const char *columnName ) {
220  rodsLog( LOG_ERROR, "sTable table full %d", CAT_TOO_MANY_TABLES );
221  return CAT_TOO_MANY_TABLES;
222  }
223  snprintf( Columns[nColumns].tableName, sizeof( Columns[nColumns].tableName ), "%s", tableName );
224  snprintf( Columns[nColumns].columnName, sizeof( Columns[nColumns].columnName ), "%s", columnName );
225  Columns[nColumns].defineValue = defineVal;
226  if ( debug > 1 ) printf( "column %d is %d %s %s\n",
227  nColumns, defineVal, tableName, columnName );
228  nColumns++;
229  return 0;
230 }
231 
232 /* given a defineValue, return the table and column names;
233  called from icatGeneralUpdate functions */
234 int
235 sGetColumnInfo( int defineVal, char **tableName, char **columnName ) {
236  int i;
237  for ( i = 0; i < nColumns; i++ ) {
238  if ( Columns[i].defineValue == defineVal ) {
241  return 0;
242  }
243  }
244  return CAT_INVALID_ARGUMENT;
245 }
246 
247 
248 /* Determine if a table is present in some sqlText. The table can be
249  a simple table name, or of the form "tableName1 tableName2", where
250  1 is being aliased to 2. If the input table is just one token,
251  then even if it matches a table in the tableName1 position, it is
252  not a match.
253  */
254 int
255 tablePresent( char *table, char *sqlText ) {
256  int tokens, blank;
257  char *cp1, *cp2;
258 
259  if ( debug > 1 ) {
260  printf( "tablePresent table:%s:\n", table );
261  }
262  if ( debug > 1 ) {
263  printf( "tablePresent sqlText:%s:\n", sqlText );
264  }
265 
266  if ( strstr( sqlText, table ) == NULL ) {
267  if ( debug > 1 ) {
268  printf( "tablePresent return 0 (simple)\n" );
269  }
270  return ( 0 ); /* simple case */
271  }
272 
273  tokens = 0;
274  blank = 1;
275  cp1 = table;
276  for ( ; *cp1 != '\0' && *cp1 != ','; cp1++ ) {
277  if ( *cp1 == ' ' ) {
278  if ( blank == 0 ) {
279  tokens++;
280  }
281  blank = 1;
282  }
283  else {
284  blank = 0;
285  }
286  }
287  if ( blank == 0 ) {
288  tokens++;
289  }
290 
291  if ( debug > 1 ) {
292  printf( "tablePresent tokens=%d\n", tokens );
293  }
294  if ( tokens == 2 ) {
295  return ( 1 ); /* 2 tokens and did match, is present */
296  }
297 
298  /* have to check if the token appears in the first or second position */
299  blank = 1;
300  cp1 = sqlText;
301  for ( ;; ) {
302  cp2 = strstr( cp1, table );
303  if ( cp2 == NULL ) {
304  return 0;
305  }
306  tokens = 0;
307  for ( ; *cp2 != '\0' && *cp2 != ','; cp2++ ) {
308  if ( *cp2 == ' ' ) {
309  if ( blank == 0 ) {
310  tokens++;
311  }
312  blank = 1;
313  }
314  else {
315  blank = 0;
316  }
317  }
318  if ( blank == 0 ) {
319  tokens++;
320  }
321  if ( tokens == 1 ) {
322  return 1;
323  }
324  cp1 = cp2;
325  }
326 }
327 
328 /*
329 tScan - tree Scan
330 */
331 int
332 tScan( int table, int link ) {
333  int thisKeep;
334  int subKeep;
335  int i;
336 
337  if ( debug > 1 ) {
338  printf( "%d tScan\n", table );
339  }
340 
341  thisKeep = 0;
342  if ( table < 0 || static_cast<std::size_t>(table) >= sizeof( Tables ) / sizeof( *Tables ) ) {
343  printf( "index %d out of bounds.", table );
344  return -1;
345  }
346 
347  if ( Tables[table].flag == 1 ) {
348  thisKeep = 1;
349  Tables[table].flag = 2;
350  nToFind--;
351  if ( debug > 1 ) {
352  printf( "nToFind decremented, now=%d\n", nToFind );
353  }
354  thisKeep = 1;
355  if ( nToFind <= 0 ) {
356  return thisKeep;
357  }
358  }
359  else {
360  if ( Tables[table].flag != 0 ) { /* not still seeking this one */
361  if ( debug > 1 ) {
362  printf( "%d returning flag=%d\n", table, Tables[table].flag );
363  }
364  return 0;
365  }
366  }
367  if ( Tables[table].cycler == 1 ) {
368  if ( debug > 1 ) {
369  printf( "%d returning cycler\n", table );
370  }
371  return ( thisKeep ); /* do no more for cyclers */
372  }
373 
374  Tables[table].flag = 3; /* Done with this one, skip it if found again */
375 
376  for ( i = 0; i < nLinks; i++ ) {
377  if ( Links[i].table1 == table && link != i ) {
378  if ( debug > 1 ) {
379  printf( "%d trying link %d forward\n", table, i );
380  }
381  subKeep = tScan( Links[i].table2, i );
382  if ( debug > 1 ) printf( "subKeep %d, this table %d, link %d, table2 %d\n",
383  subKeep, table, i, Links[i].table2 );
384  if ( subKeep ) {
385  thisKeep = 1;
386  if ( debug > 1 ) {
387  printf( "%d use link %d\n", table, i );
388  }
389  if ( strlen( whereSQL ) > 6 ) {
390  if ( !rstrcat( whereSQL, " AND ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
391  }
392  if ( !rstrcat( whereSQL, Links[i].connectingSQL, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
393  if ( !rstrcat( whereSQL, " ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
394  if ( tablePresent( Tables[Links[i].table2].tableAlias, fromSQL ) == 0 ) {
395  if ( !rstrcat( fromSQL, ", ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
396  if ( !rstrcat( fromSQL, Tables[Links[i].table2].tableAlias,
397  MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
398  if ( !rstrcat( fromSQL, " ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
399  }
400  if ( tablePresent( Tables[Links[i].table1].tableAlias, fromSQL ) == 0 ) {
401  if ( !rstrcat( fromSQL, ", ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
402  if ( !rstrcat( fromSQL, Tables[Links[i].table1].tableAlias,
403  MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
404  if ( !rstrcat( fromSQL, " ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
405  }
406  if ( debug > 1 ) {
407  printf( "added (2) to fromSQL: %s\n", fromSQL );
408  }
409  if ( nToFind <= 0 ) {
410  return thisKeep;
411  }
412  }
413  }
414  }
415  for ( i = 0; i < nLinks; i++ ) {
416  if ( Links[i].table2 == table && link != i ) {
417  if ( debug > 1 ) {
418  printf( "%d trying link %d backward\n", table, i );
419  }
420  subKeep = tScan( Links[i].table1, i );
421  if ( debug > 1 ) printf( "subKeep %d, this table %d, link %d, table1 %d\n",
422  subKeep, table, i, Links[i].table1 );
423  if ( subKeep ) {
424  thisKeep = 1;
425  if ( debug > 1 ) {
426  printf( "%d use link %d\n", table, i );
427  }
428  if ( strlen( whereSQL ) > 6 ) {
429  if ( !rstrcat( whereSQL, " AND ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
430  }
431  if ( !rstrcat( whereSQL, Links[i].connectingSQL, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
432  if ( !rstrcat( whereSQL, " ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
433  if ( tablePresent( Tables[Links[i].table2].tableAlias, fromSQL ) == 0 ) {
434  if ( !rstrcat( fromSQL, ", ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
435  if ( !rstrcat( fromSQL, Tables[Links[i].table2].tableAlias,
436  MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
437  if ( !rstrcat( fromSQL, " ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
438  }
439  if ( tablePresent( Tables[Links[i].table1].tableAlias, fromSQL ) == 0 ) {
440  if ( !rstrcat( fromSQL, ", ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
441  if ( !rstrcat( fromSQL, Tables[Links[i].table1].tableAlias,
442  MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
443  if ( !rstrcat( fromSQL, " ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
444  }
445  if ( debug > 1 ) {
446  printf( "added (3) to fromSQL: %s\n", fromSQL );
447  }
448  if ( nToFind <= 0 ) {
449  return thisKeep;
450  }
451  }
452  }
453  }
454  if ( debug > 1 ) {
455  printf( "%d returning %d\n", table, thisKeep );
456  }
457  return thisKeep;
458 }
459 
460 /* prelim test routine, find a subtree between two tables */
461 int
462 sTest( int i1, int i2 ) {
463  int i;
464  int keepVal;
465 
466  if ( firstCall ) {
467  icatGeneralQuerySetup(); /* initialize */
468  }
469  firstCall = 0;
470 
471  for ( i = 0; i < nTables; i++ ) {
472  Tables[i].flag = 0;
473  if ( i == i1 || i == i2 ) {
474  Tables[i].flag = 1;
475  }
476  }
477  nToFind = 2;
478  keepVal = tScan( i1, -1 );
479  if ( keepVal != 1 || nToFind != 0 ) {
480  printf( "error failed to link %d to %d\n", i1, i2 );
481  }
482  else {
483  printf( "SUCCESS linking %d to %d\n", i1, i2 );
484  }
485  return 0;
486 }
487 
488 int sTest2( int i1, int i2, int i3 ) {
489  int i;
490  int keepVal;
491 
492  if ( firstCall ) {
493  icatGeneralQuerySetup(); /* initialize */
494  }
495  firstCall = 0;
496 
497  for ( i = 0; i < nTables; i++ ) {
498  Tables[i].flag = 0;
499  if ( i == i1 || i == i2 || i == i3 ) {
500  Tables[i].flag = 1;
501  }
502  }
503  nToFind = 3;
504  keepVal = tScan( i1, -1 );
505  if ( keepVal != 1 || nToFind != 0 ) {
506  printf( "error failed to link %d, %d and %d\n", i1, i2, i3 );
507  }
508  else {
509  printf( "SUCCESS linking %d, %d, %d\n", i1, i2, i3 );
510  }
511  return 0;
512 }
513 
514 
515 /*
516 tCycleChk - tree Cycle Checker
517 */
518 int
519 tCycleChk( int table, int link, int thisTreeNum ) {
520  int thisKeep;
521  int subKeep;
522  int i;
523 
524  if ( debug > 1 ) {
525  printf( "%d tCycleChk\n", table );
526  }
527 
528  thisKeep = 0;
529 
530  if ( Tables[table].flag != 0 ) {
531  if ( Tables[table].flag == thisTreeNum ) {
532  if ( debug > 1 ) {
533  printf( "Found cycle at node %d\n", table );
534  }
535  return 1;
536  }
537  }
538  Tables[table].flag = thisTreeNum;
539 
540  if ( Tables[table].cycler == 1 ) {
541  if ( debug > 1 ) {
542  printf( "%d returning cycler\n", table );
543  }
544  return ( thisKeep ); /* do no more for cyclers */
545  }
546 
547  for ( i = 0; i < nLinks; i++ ) {
548  if ( Links[i].table1 == table && link != i ) {
549  if ( debug > 1 ) {
550  printf( "%d trying link %d forward\n", table, i );
551  }
552  subKeep = tCycleChk( Links[i].table2, i, thisTreeNum );
553  if ( subKeep ) {
554  thisKeep = 1;
555  if ( debug > 1 ) printf( "%d use link %d tree %d\n", table, i,
556  thisTreeNum );
557  return thisKeep;
558  }
559  }
560  }
561  for ( i = 0; i < nLinks; i++ ) {
562  if ( Links[i].table2 == table && link != i ) {
563  if ( debug > 1 ) {
564  printf( "%d trying link %d backward\n", table, i );
565  }
566  subKeep = tCycleChk( Links[i].table1, i, thisTreeNum );
567  if ( subKeep ) {
568  thisKeep = 1;
569  if ( debug > 1 ) {
570  printf( "%d use link %d\n", table, i );
571  }
572  return thisKeep;
573  }
574  }
575  }
576  if ( debug > 1 ) {
577  printf( "%d returning %d\n", table, thisKeep );
578  }
579  return thisKeep;
580 }
581 
582 /*
583  This routine goes thru the tables and links looking for cycles. If
584  there are any cycles, it is a problem as that would mean that there
585  are multiple paths between nodes. So this needs to be run when
586  tables or links are changed, but once confirmed that all is OK does
587  not need to be run again.
588 */
589 int findCycles( int startTable ) {
590  int i, status;
591  int treeNum;
592 
593  if ( firstCall ) {
594  icatGeneralQuerySetup(); /* initialize */
595  }
596  firstCall = 0;
597 
598  for ( i = 0; i < nTables; i++ ) {
599  Tables[i].flag = 0;
600  }
601  treeNum = 0;
602 
603  if ( startTable != 0 ) {
604  if ( startTable > nTables ) {
605  return CAT_INVALID_ARGUMENT;
606  }
607  treeNum++;
608  status = tCycleChk( startTable, -1, treeNum );
609  if ( debug > 1 ) {
610  printf( "tree %d status %d\n", treeNum, status );
611  }
612  if ( status ) {
613  return status;
614  }
615  }
616 
617  for ( i = 0; i < nTables; i++ ) {
618  if ( Tables[i].flag == 0 ) {
619  treeNum++;
620  status = tCycleChk( i, -1, treeNum );
621  if ( debug > 1 ) {
622  printf( "tree %d status %d\n", treeNum, status );
623  }
624  if ( status ) {
625  return status;
626  }
627  }
628  }
629  return 0;
630 }
631 
632 /*
633  Given a column value (from the #define's), select the corresponding
634  table. At the same time, if sel==1, also add another select field to
635  selectSQL, fromSQL, whereSQL, and groupBySQL (which is sometimes
636  used). if selectOption is set, then input may be one of the SELECT_*
637  modifiers (min, max, etc).
638  If the castOption is set, cast the column to a decimal (numeric).
639  */
640 int setTable( int column, int sel, int selectOption, int castOption ) {
641  int colIx;
642  int i;
643  int selectOptFlag;
644 
645  colIx = -1;
646  for ( i = 0; i < nColumns; i++ ) {
647  if ( Columns[i].defineValue == column ) {
648  colIx = i;
649  }
650  }
651  if ( colIx == -1 ) {
652  return CAT_UNKNOWN_TABLE;
653  }
654 
655  for ( i = 0; i < nTables; i++ ) {
656  if ( strcmp( Tables[i].tableName, Columns[colIx].tableName ) == 0 ) {
657  if ( Tables[i].flag == 0 ) {
658  nToFind++;
660  Tables[i].tableAbbrev[1] = '\0';
661  tableAbbrevs++;
662  }
663  Tables[i].flag = 1;
664  if ( sel ) {
665  if ( selectSQLInitFlag == 0 ) {
666  if ( !rstrcat( selectSQL, ",", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
667  }
668  selectSQLInitFlag = 0; /* no longer empty of columns */
669 
670  selectOptFlag = 0;
671  if ( selectOption != 0 ) {
672  if ( selectOption == SELECT_MIN ) {
673  if ( !rstrcat( selectSQL, "min(", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
674  selectOptFlag = 1;
675  }
676  if ( selectOption == SELECT_MAX ) {
677  if ( !rstrcat( selectSQL, "max(", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
678  selectOptFlag = 1;
679  }
680  if ( selectOption == SELECT_SUM ) {
681  if ( !rstrcat( selectSQL, "sum(", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
682  selectOptFlag = 1;
683  }
684  if ( selectOption == SELECT_AVG ) {
685  if ( !rstrcat( selectSQL, "avg(", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
686  selectOptFlag = 1;
687  }
688  if ( selectOption == SELECT_COUNT ) {
689  if ( !rstrcat( selectSQL, "count(", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
690  selectOptFlag = 1;
691  }
692  }
694  if ( !rstrcat( selectSQL, ".", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
696  if ( !rstrcat( selectSQL, " ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
697  if ( selectOptFlag ) {
698  if ( !rstrcat( selectSQL, ") ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
699  mightNeedGroupBy = 1;
700  }
701  else {
702  if ( strlen( groupBySQL ) > 10 ) {
703  if ( !rstrcat( groupBySQL, ",", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
704  }
706  if ( !rstrcat( groupBySQL, ".", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
708  if ( !rstrcat( groupBySQL, " ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
709  }
710 
711  if ( tablePresent( Tables[i].tableAlias, fromSQL ) == 0 ) {
712  if ( fromCount ) {
713  if ( !rstrcat( fromSQL, ", ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
714  }
715  else {
716  if ( !rstrcat( fromSQL, " ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
717  }
718  fromCount++;
719  if ( !rstrcat( fromSQL, Tables[i].tableAlias, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
720  if ( !rstrcat( fromSQL, " ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
721  }
722  if ( debug > 1 ) {
723  printf( "added (1) to fromSQL: %s\n", fromSQL );
724  }
725  }
726  else {
727 
728  if ( strlen( whereSQL ) > 6 ) {
729  if ( !rstrcat( whereSQL, " AND ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
730  }
731  if ( castOption == 1 ) {
732  if ( !rstrcat( whereSQL, "cast (", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
733  }
734 
735  if ( doUpperCase == 1 && castOption == 0 ) {
736  if ( !rstrcat( whereSQL, "upper (", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
737  }
738 
740  if ( !rstrcat( whereSQL, ".", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
741  if ( !rstrcat( whereSQL, Columns[colIx].columnName, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
742 
743  if ( doUpperCase == 1 && castOption == 0 ) {
744  if ( !rstrcat( whereSQL, " )", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
745  }
746 
747  if ( castOption == 1 ) {
748  /* For PostgreSQL and MySQL, 'decimal' seems to work
749  fine but for Oracle 'number' is needed to handle
750  both integer and floating point. */
751 #if ORA_ICAT
752  if ( !rstrcat( whereSQL, " as number)", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
753 #else
754  if ( !rstrcat( whereSQL, " as decimal)", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
755 #endif
756  }
757  }
758  if ( debug > 1 ) {
759  printf( "table index=%d, nToFind=%d\n", i, nToFind );
760  }
761  return i;
762  }
763  }
764  return -1;
765 }
766 
767 /*
768  When there are multiple AVU conditions, need to adjust the SQL.
769  */
770 void
771 handleMultiDataAVUConditions( int nConditions ) {
772  int i;
773  char *firstItem, *nextItem;
774  char nextStr[20];
775 
776  /* In the whereSQL, change r_data_meta_main.meta_attr_name to
777  r_data_meta_mnNN.meta_attr_name, where NN is index. First one
778  is OK, subsequent ones need a new name for each. */
779  firstItem = strstr( whereSQL, "r_data_meta_main.meta_attr_name" );
780  if ( firstItem != NULL ) {
781  *firstItem = 'x'; /* temporarily change 1st string */
782  }
783  for ( i = 2; i <= nConditions; i++ ) {
784  nextItem = strstr( whereSQL, "r_data_meta_main.meta_attr_name" );
785  if ( nextItem != NULL ) {
786  snprintf( nextStr, sizeof nextStr, "n%2.2d", i );
787  *( nextItem + 13 ) = nextStr[0]; /* replace "ain" in main */
788  *( nextItem + 14 ) = nextStr[1]; /* with nNN */
789  *( nextItem + 15 ) = nextStr[2];
790  }
791  }
792  if ( firstItem != NULL ) {
793  *firstItem = 'r'; /* put it back */
794  }
795 
796  /* Do similar for r_data_meta_main.meta_attr_value. */
797  firstItem = strstr( whereSQL, "r_data_meta_main.meta_attr_value" );
798  if ( firstItem != NULL ) {
799  *firstItem = 'x'; /* temporarily change 1st string */
800  }
801  for ( i = 2; i <= nConditions; i++ ) {
802  nextItem = strstr( whereSQL, "r_data_meta_main.meta_attr_value" );
803  if ( nextItem != NULL ) {
804  snprintf( nextStr, sizeof nextStr, "n%2.2d", i );
805  *( nextItem + 13 ) = nextStr[0]; /* replace "ain" in main */
806  *( nextItem + 14 ) = nextStr[1]; /* with nNN */
807  *( nextItem + 15 ) = nextStr[2];
808  }
809  }
810  if ( firstItem != NULL ) {
811  *firstItem = 'r'; /* put it back */
812  }
813 
814 
815  /* In the fromSQL, add items for r_data_metamapNN and
816  r_data_meta_mnNN */
817  for ( i = 2; i <= nConditions; i++ ) {
818  char newStr[100];
819  snprintf( newStr, sizeof newStr,
820  ", R_OBJT_METAMAP r_data_metamap%d, R_META_MAIN r_data_meta_mn%2.2d ",
821  i, i );
822  if ( !rstrcat( fromSQL, newStr, MAX_SQL_SIZE_GQ ) ) { return; }
823  }
824 
825  /* In the whereSQL, add items for
826  r_data_metamapNN.meta_id = r_data_meta_maNN.meta_id and
827  R_DATA_MAIN.data_id = r_data_metamap2.object_id
828  */
829  for ( i = 2; i <= nConditions; i++ ) {
830  char newStr[100];
831  snprintf( newStr, sizeof newStr,
832  " AND r_data_metamap%d.meta_id = r_data_meta_mn%2.2d.meta_id", i, i );
833  if ( !rstrcat( whereSQL, newStr, MAX_SQL_SIZE_GQ ) ) { return; }
834  snprintf( newStr, sizeof newStr,
835  " AND R_DATA_MAIN.data_id = r_data_metamap%d.object_id ", i );
836  if ( !rstrcat( whereSQL, newStr, MAX_SQL_SIZE_GQ ) ) { return; }
837  }
838 }
839 
840 /*
841  When there are multiple AVU conditions on Collections, need to adjust the SQL.
842  */
843 void
844 handleMultiCollAVUConditions( int nConditions ) {
845  int i;
846  char *firstItem, *nextItem;
847  char nextStr[20];
848 
849  /* In the whereSQL, change r_coll_meta_main.meta_attr_name to
850  r_coll_meta_mnNN.meta_attr_name, where NN is index. First one
851  is OK, subsequent ones need a new name for each. */
852  firstItem = strstr( whereSQL, "r_coll_meta_main.meta_attr_name" );
853  if ( firstItem != NULL ) {
854  *firstItem = 'x'; /* temporarily change 1st string */
855  }
856  for ( i = 2; i <= nConditions; i++ ) {
857  nextItem = strstr( whereSQL, "r_coll_meta_main.meta_attr_name" );
858  if ( nextItem != NULL ) {
859  snprintf( nextStr, sizeof nextStr, "n%2.2d", i );
860  *( nextItem + 13 ) = nextStr[0]; /* replace "ain" in main */
861  *( nextItem + 14 ) = nextStr[1]; /* with nNN */
862  *( nextItem + 15 ) = nextStr[2];
863  }
864  }
865  if ( firstItem != NULL ) {
866  *firstItem = 'r'; /* put it back */
867  }
868 
869  /* Do similar for r_coll_meta_main.meta_attr_value. */
870  firstItem = strstr( whereSQL, "r_coll_meta_main.meta_attr_value" );
871  if ( firstItem != NULL ) {
872  *firstItem = 'x'; /* temporarily change 1st string */
873  }
874  for ( i = 2; i <= nConditions; i++ ) {
875  nextItem = strstr( whereSQL, "r_coll_meta_main.meta_attr_value" );
876  if ( nextItem != NULL ) {
877  snprintf( nextStr, sizeof nextStr, "n%2.2d", i );
878  *( nextItem + 13 ) = nextStr[0]; /* replace "ain" in main */
879  *( nextItem + 14 ) = nextStr[1]; /* with nNN */
880  *( nextItem + 15 ) = nextStr[2];
881  }
882  }
883  if ( firstItem != NULL ) {
884  *firstItem = 'r'; /* put it back */
885  }
886 
887 
888  /* In the fromSQL, add items for r_coll_metamapNN and
889  r_coll_meta_mnNN */
890  for ( i = 2; i <= nConditions; i++ ) {
891  char newStr[100];
892  snprintf( newStr, sizeof newStr,
893  ", R_OBJT_METAMAP r_coll_metamap%d, R_META_MAIN r_coll_meta_mn%2.2d ",
894  i, i );
895  if ( !rstrcat( fromSQL, newStr, MAX_SQL_SIZE_GQ ) ) { return; }
896  }
897 
898  /* In the whereSQL, add items for
899  r_coll_metamapNN.meta_id = r_coll_meta_maNN.meta_id and
900  R_COLL_MAIN.coll_id = r_coll_metamap2.object_id
901  */
902  for ( i = 2; i <= nConditions; i++ ) {
903  char newStr[100];
904  snprintf( newStr, sizeof newStr,
905  " AND r_coll_metamap%d.meta_id = r_coll_meta_mn%2.2d.meta_id", i, i );
906  if ( !rstrcat( whereSQL, newStr, MAX_SQL_SIZE_GQ ) ) { return; }
907  snprintf( newStr, sizeof newStr,
908  " AND R_COLL_MAIN.coll_id = r_coll_metamap%d.object_id ", i );
909  if ( !rstrcat( whereSQL, newStr, MAX_SQL_SIZE_GQ ) ) { return; }
910  }
911 }
912 
913 /*
914  Check if this is a compound condition, that is if there is a && or ||
915  outside of single quotes. Previously the corresponding test was just
916  to see if && or || existed in the string, but if the name
917  (data-object or other) included && it would be mistaken. At this
918  level, names are always in quotes so we can just verify that && or ||
919  is there and not quoted.
920  */
921 int
922 compoundConditionSpecified( char *condition ) {
923  char myCondition[MAX_NAME_LEN * 2];
924  int quote;
925  char *cptr;
926 
927  /* Simple case, not in the condition at all */
928  if ( strstr( condition, "||" ) == NULL &&
929  strstr( condition, "&&" ) == NULL ) {
930  return 0;
931  }
932 
933  /* Make a copy of the condition and erase the quoted strings */
934  snprintf( myCondition, sizeof( myCondition ), "%s", condition );
935  for ( cptr = myCondition, quote = 0; *cptr != '\0'; cptr++ ) {
936  if ( *cptr == '\'' ) {
937  if ( quote == 0 ) {
938  quote = 1;
939  }
940  else {
941  quote = 0;
942  }
943  *cptr = ' ';
944  }
945  if ( quote == 1 ) {
946  *cptr = ' ';
947  }
948  }
949 
950  /* And now test again */
951  if ( strstr( myCondition, "||" ) == NULL &&
952  strstr( myCondition, "&&" ) == NULL ) {
953  return 0;
954  }
955  return 1;
956 }
957 
958 /* When there's a compound condition, need to put () around it, use the
959  tablename.column for each part, and put OR or AND between.
960  Uses and updates whereSQL in addition to the arguments.
961 */
962 int
963 handleCompoundCondition( char *condition, int prevWhereLen ) {
964  char tabAndColumn[MAX_SQL_SIZE_GQ];
965  char condPart1[MAX_NAME_LEN * 2];
966  static char condPart2[MAX_NAME_LEN * 2];
967  static char conditionsForBind[MAX_NAME_LEN * 2];
968  static int conditionsForBindIx = 0;
969  int status;
970 
971  if ( prevWhereLen < 0 ) { /* reinitialize */
972  conditionsForBindIx = 0;
973  return 0;
974  }
975 
976  /* If there's an AND that was appended, need to include it */
977  int i = prevWhereLen;
978  while ( whereSQL[i] == ' ' ) {
979  i++;
980  }
981  if ( strncmp( whereSQL + i, "AND", 3 ) == 0 ) {
982  prevWhereLen = i + 3;
983  }
984 
985  if ( !rstrcpy( tabAndColumn, ( char * )&whereSQL[prevWhereLen], MAX_SQL_SIZE_GQ ) ) {
986  return USER_STRLEN_TOOLONG;
987  }
988 
989  whereSQL[prevWhereLen] = '\0'; /* reset whereSQL to previous spot */
990  if ( !rstrcat( whereSQL, " ( ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
991 
992  if ( !rstrcpy( condPart2, condition, MAX_NAME_LEN * 2 ) ) {
993  return USER_STRLEN_TOOLONG;
994  }
995 
996  while ( true ) {
997  if ( !rstrcpy( condPart1, condPart2, MAX_NAME_LEN * 2 ) ) {
998  return USER_STRLEN_TOOLONG;
999  }
1000 
1001  char* orptr{};
1002  char* andptr{};
1003 
1004  {
1005  std::string tmp = condPart1;
1006 
1007  // Masking the query arguments (characters surrounded by quotes) is
1008  // required in case the arguments contain character sequences that
1009  // can trip up the parser (e.g. "&&" and "||"). This allows the parser
1010  // to find the correct location of the "and" and "or" operators.
1011  mask_query_arguments(tmp);
1012 
1013  auto pos = tmp.find("||");
1014 
1015  if (std::string::npos != pos) {
1016  orptr = condPart1 + pos;
1017  }
1018 
1019  pos = tmp.find("&&");
1020 
1021  if (std::string::npos != pos) {
1022  andptr = condPart1 + pos;
1023  }
1024  }
1025 
1026  char *cptr{};
1027  int type = 0;
1028  if ( orptr != NULL && ( andptr == NULL || orptr < andptr ) ) {
1029  cptr = orptr;
1030  type = 1;
1031  }
1032  else if ( andptr != NULL && ( orptr == NULL || andptr < orptr ) ) {
1033  cptr = andptr;
1034  type = 2;
1035  }
1036  else {
1037  break;
1038  }
1039  *cptr = '\0';
1040  cptr += 2; /* past the && or || */
1041  if ( !rstrcpy( condPart2, cptr, MAX_NAME_LEN * 2 ) ) {
1042  return USER_STRLEN_TOOLONG;
1043  }
1044 
1045  if ( !rstrcat( whereSQL, tabAndColumn, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1046  if ( !rstrcpy( ( char* )&conditionsForBind[conditionsForBindIx], condPart1,
1047  ( MAX_SQL_SIZE_GQ * 2 ) - conditionsForBindIx ) ) {
1048  return USER_STRLEN_TOOLONG;
1049  }
1050  status = insertWhere( ( char* )&conditionsForBind[conditionsForBindIx], 0 );
1051  if ( status ) {
1052  return status;
1053  }
1054  conditionsForBindIx += strlen( condPart1 ) + 1;
1055 
1056  if ( type == 1 ) {
1057  if ( !rstrcat( whereSQL, " OR ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1058  }
1059  else if ( type == 2 ) {
1060  if ( !rstrcat( whereSQL, " AND ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1061  }
1062  }
1063 
1064  if ( !rstrcat( whereSQL, tabAndColumn, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1065  status = insertWhere( condPart2, 0 );
1066  if ( status ) {
1067  return status;
1068  }
1069 
1070  if ( !rstrcat( whereSQL, " ) ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1071  return 0;
1072 }
1073 
1074 /* Set the orderBySQL clause if needed */
1075 void
1076 setOrderBy( genQueryInp_t genQueryInp, int column ) {
1077  int i, j;
1078  int selectOpt, isAggregated;
1079  for ( i = 0; i < genQueryInp.selectInp.len; i++ ) {
1080  if ( genQueryInp.selectInp.inx[i] == column ) {
1081  selectOpt = genQueryInp.selectInp.value[i] & 0xf;
1082  isAggregated = 0;
1083  if ( selectOpt == SELECT_MIN ) {
1084  isAggregated = 1;
1085  }
1086  if ( selectOpt == SELECT_MAX ) {
1087  isAggregated = 1;
1088  }
1089  if ( selectOpt == SELECT_SUM ) {
1090  isAggregated = 1;
1091  }
1092  if ( selectOpt == SELECT_AVG ) {
1093  isAggregated = 1;
1094  }
1095  if ( selectOpt == SELECT_COUNT ) {
1096  isAggregated = 1;
1097  }
1098  if ( isAggregated == 0 ) {
1099  for ( j = 0; j < nColumns; j++ ) {
1100  if ( Columns[j].defineValue == column ) {
1101  if ( strlen( orderBySQL ) > 10 ) {
1102  if ( !rstrcat( orderBySQL, ", ", MAX_SQL_SIZE_GQ ) ) { return; }
1103  }
1104  if ( !rstrcat( orderBySQL, Columns[j].tableName, MAX_SQL_SIZE_GQ ) ) { return; }
1105  if ( !rstrcat( orderBySQL, ".", MAX_SQL_SIZE_GQ ) ) { return; }
1106  if ( !rstrcat( orderBySQL, Columns[j].columnName, MAX_SQL_SIZE_GQ ) ) { return; }
1107  break;
1108  }
1109  }
1110  }
1111  }
1112  }
1113 }
1114 
1115 /*
1116  Set the user-requested order-by clauses (if any)
1117  */
1118 void
1120  int i, j, done;
1121  for ( i = 0; i < genQueryInp.selectInp.len; i++ ) {
1122  if ( ( genQueryInp.selectInp.value[i] & ORDER_BY ) ||
1123  ( genQueryInp.selectInp.value[i] & ORDER_BY_DESC ) ) {
1124  done = 0;
1125  for ( j = 0; j < nColumns && done == 0; j++ ) {
1126  if ( Columns[j].defineValue == genQueryInp.selectInp.inx[i] ) {
1127  if ( strlen( orderBySQL ) > 10 ) {
1128  if ( !rstrcat( orderBySQL, ", ", MAX_SQL_SIZE_GQ ) ) { return ; }
1129  }
1130  if ( !rstrcat( orderBySQL, Columns[j].tableName, MAX_SQL_SIZE_GQ ) ) { return ; }
1131  if ( !rstrcat( orderBySQL, ".", MAX_SQL_SIZE_GQ ) ) { return ; }
1132  if ( !rstrcat( orderBySQL, Columns[j].columnName, MAX_SQL_SIZE_GQ ) ) { return ; }
1133  if ( genQueryInp.selectInp.value[i] & ORDER_BY_DESC ) {
1134  if ( !rstrcat( orderBySQL, " DESC ", MAX_SQL_SIZE_GQ ) ) { return ; }
1135  }
1136  done = 1;
1137  }
1138  }
1139  }
1140  }
1141 }
1142 
1143 int
1144 setBlank( char *string, int count ) {
1145  int i;
1146  char *cp;
1147  for ( cp = string, i = 0; i < count; i++ ) {
1148  *cp++ = ' ';
1149  }
1150  return 0;
1151 }
1152 
1153 /*
1154 Verify that a condition is a valid SQL condition
1155  */
1156 int
1157 checkCondition( char *condition ) {
1158  char tmpStr[25];
1159  char *cp;
1160 
1161  if ( !rstrcpy( tmpStr, condition, 20 ) ) {
1162  return USER_STRLEN_TOOLONG;
1163  }
1164  for ( cp = tmpStr; *cp != '\0'; cp++ ) {
1165  if ( *cp == '<' ) {
1166  *cp = ' ';
1167  }
1168  if ( *cp == '>' ) {
1169  *cp = ' ';
1170  }
1171  if ( *cp == '=' ) {
1172  *cp = ' ';
1173  }
1174  if ( *cp == '!' ) {
1175  *cp = ' ';
1176  }
1177  }
1178  cp = strstr( tmpStr, "begin_of" );
1179  if ( cp != NULL ) {
1180  setBlank( cp, 8 );
1181  }
1182  cp = strstr( tmpStr, "parent_of" );
1183  if ( cp != NULL ) {
1184  setBlank( cp, 9 );
1185  }
1186  cp = strstr( tmpStr, "not" );
1187  if ( cp != NULL ) {
1188  setBlank( cp, 3 );
1189  }
1190  cp = strstr( tmpStr, "NOT" );
1191  if ( cp != NULL ) {
1192  setBlank( cp, 3 );
1193  }
1194  cp = strstr( tmpStr, "between" );
1195  if ( cp != NULL ) {
1196  setBlank( cp, 7 );
1197  }
1198  cp = strstr( tmpStr, "BETWEEN" );
1199  if ( cp != NULL ) {
1200  setBlank( cp, 7 );
1201  }
1202  cp = strstr( tmpStr, "like" );
1203  if ( cp != NULL ) {
1204  setBlank( cp, 4 );
1205  }
1206  cp = strstr( tmpStr, "LIKE" );
1207  if ( cp != NULL ) {
1208  setBlank( cp, 4 );
1209  }
1210  cp = strstr( tmpStr, "in" );
1211  if ( cp != NULL ) {
1212  setBlank( cp, 2 );
1213  }
1214  cp = strstr( tmpStr, "IN" );
1215  if ( cp != NULL ) {
1216  setBlank( cp, 2 );
1217  }
1218 
1219  for ( cp = tmpStr; *cp != '\0'; cp++ ) {
1220  if ( *cp != ' ' ) {
1221  return CAT_INVALID_ARGUMENT;
1222  }
1223  }
1224  return 0;
1225 }
1226 
1227 /*
1228 add an IN clause to the whereSQL string for the Parent_Of option
1229  */
1230 int
1232 {
1233  // This vector holds all of the components of the path
1234  // in the parameter inArg, with no slashes.
1235  std::vector<std::string> paths;
1236 
1237  // The purpose of this vector of strings is to stick around until all
1238  // references to the strings included are gone -- the cllBindVars[] array
1239  // of pointers to null terminated strings is filled with these strings
1240  // which cannot be removed until the next call to this function.
1241  static std::vector<std::string> inStringVec;
1242  static bool reset_vector = false;
1243 
1244  // Save the current separator -- it's used in more than on place below
1245  std::string separator(irods::get_virtual_path_separator());
1246 
1247  // Making sure that the separator has a single char
1248  if (separator.size() > 1)
1249  {
1250  rodsLog( LOG_ERROR, "irods::get_virtual_path_separator() returned a string with more than one character.");
1251  return BAD_FUNCTION_CALL;
1252  }
1253 
1254  try
1255  {
1256  std::string stringInArg(const_cast<const char *>(inArg));
1257 
1258  // The fourth parameter below will remove adjacent separators
1259  boost::algorithm::split(paths, stringInArg, boost::is_any_of(separator), boost::algorithm::token_compress_on);
1260  }
1261  catch ( const boost::bad_function_call& )
1262  {
1263  rodsLog( LOG_ERROR, "boost::split threw boost::bad_function_call" );
1264  return BAD_FUNCTION_CALL;
1265  }
1266 
1267  // Collect all the parameter path components in order
1268  // from left to right. Starting from the second call to
1269  // this function, the vector is cleared as explained above.
1270  if (reset_vector)
1271  {
1272  inStringVec.clear();
1273  }
1274  reset_vector = true;
1275 
1276  // Put together all the paths included in the parameter path
1277  // and save them in the static vector. These strings will
1278  // be assigned to the global bind variable array used
1279  // in the WHERE clause.
1280  //
1281  // Thusly, the path "/tempZone/trash/home/public" for example, will become:
1282  //
1283  // inStringVec[0] = /
1284  // inStringVec[1] = /tempZone
1285  // inStringVec[2] = /tempZone/trash
1286  // inStringVec[3] = /tempZone/trash/home
1287  // inStringVec[4] = /tempZone/trash/home/public
1288  for (size_t si = 0; si < paths.size(); si++)
1289  {
1290  std::string path;
1291  bool need_slash = false;
1292 
1293  for (size_t j = 0; j <= si; j++)
1294  {
1295  if (paths[j].empty()) {
1296  path += separator;
1297  need_slash = false;
1298  } else {
1299  if (need_slash) {
1300  path += separator;
1301  }
1302  path += paths[j];
1303  need_slash = true;
1304  }
1305  }
1306  inStringVec.push_back(path);
1307  }
1308 
1309  // Assemble the IN clause segment. Every path in inStringVec gets a '?'.
1310  // This string ends up looking like this: "IN (?, ?, ?, ?, ?)" where
1311  // the number of '?'s is equal to the number of paths in inStringVec.
1312  std::string whereString(" IN (");
1313  for (size_t si = 0; si < inStringVec.size(); si++)
1314  {
1315  if (si == 0) {
1316  whereString += "?";
1317  } else {
1318  whereString += ", ?";
1319  }
1320  }
1321  whereString += ")";
1322 
1323  if ( !rstrcat( whereSQL, whereString.c_str(), MAX_SQL_SIZE_GQ) ) { return USER_STRLEN_TOOLONG; }
1324 
1325  if ( cllBindVarCount + inStringVec.size() >= MAX_BIND_VARS ) {
1327  }
1328 
1329  // This assigns the static strings to the global bind variable array.
1330  for (size_t si = 0; si < inStringVec.size(); si++)
1331  {
1332  cllBindVars[cllBindVarCount++] = inStringVec[si].c_str();
1333  }
1334  return 0;
1335 }
1336 
1337 /*
1338 add an IN clause to the whereSQL string for a client IN request
1339  */
1340 int
1341 addInClauseToWhereForIn( char *inArg, int option ) {
1342  int i, len;
1343  int startIx, endIx;
1344  int nput = 0;
1345  int quoteState = 0;
1346  char tmpStr[MAX_SQL_SIZE_GQ];
1347  static char inStrings[MAX_SQL_SIZE_GQ * 2];
1348  static int inStrIx;
1349  int ncopy;
1350 
1351  if ( option == 1 ) {
1352  inStrIx = 0;
1353  return 0;
1354  }
1355  if ( !rstrcat( whereSQL, " IN (", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1356  len = strlen( inArg );
1357  for ( i = 0; i < len + 1; i++ ) {
1358  if ( inArg[i] == '\'' ) {
1359  quoteState++;
1360  if ( quoteState == 1 ) {
1361  startIx = i + 1;
1362  }
1363  if ( quoteState == 2 ) {
1364  quoteState = 0;
1365  endIx = i - 1;
1366  if ( nput == 0 ) {
1367  if ( !rstrcat( whereSQL, "?", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1368  }
1369  else {
1370  if ( !rstrcat( whereSQL, ", ?", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1371  }
1372  nput++;
1373 
1374  /* Add the quoted string as a bind variable so user can't
1375  execute arbitrary code */
1376  tmpStr[0] = '\0';
1377  ncopy = endIx - startIx + 1;
1378  rstrncat( tmpStr, ( char * )&inArg[startIx], ncopy, MAX_SQL_SIZE_GQ );
1379  if ( !rstrcpy( ( char * )&inStrings[inStrIx], tmpStr,
1380  ( MAX_SQL_SIZE_GQ * 2 ) - inStrIx ) ) {
1381  return USER_STRLEN_TOOLONG;
1382  }
1383  inStrings[inStrIx + ncopy] = '\0';
1384  if ( cllBindVarCount + 1 >= MAX_BIND_VARS ) { // JMC - backport 4848
1386  }
1387 
1388  cllBindVars[cllBindVarCount++] = ( char * )&inStrings[inStrIx];
1389  inStrIx = inStrIx + ncopy + 1;
1390  }
1391  }
1392  }
1393  if ( !rstrcat( whereSQL, ")", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1394  if ( nput == 0 ) {
1395  return CAT_INVALID_ARGUMENT;
1396  }
1397  return 0;
1398 }
1399 
1400 /*
1401 add a BETWEEN clause to the whereSQL string
1402  */
1403 int
1404 addBetweenClauseToWhere( char *inArg ) {
1405  int i, len;
1406  int startIx, endIx;
1407  int nput = 0;
1408  int quoteState = 0;
1409  char tmpStr[MAX_SQL_SIZE_GQ];
1410  static char inStrings[MAX_SQL_SIZE_GQ];
1411  int inStrIx = 0;
1412  int ncopy;
1413  if ( !rstrcat( whereSQL, " BETWEEN ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1414  len = strlen( inArg );
1415  for ( i = 0; i < len + 1; i++ ) {
1416  if ( inArg[i] == '\'' ) {
1417  quoteState++;
1418  if ( quoteState == 1 ) {
1419  startIx = i + 1;
1420  }
1421  if ( quoteState == 2 ) {
1422  quoteState = 0;
1423  endIx = i - 1;
1424  if ( nput == 0 ) {
1425  if ( !rstrcat( whereSQL, "?", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1426  }
1427  else {
1428  if ( !rstrcat( whereSQL, " AND ? ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1429  }
1430  nput++;
1431 
1432  /* Add the quoted string as a bind variable so user can't
1433  execute arbitrary code */
1434  tmpStr[0] = '\0';
1435  ncopy = endIx - startIx + 1;
1436  rstrncat( tmpStr, ( char * )&inArg[startIx], ncopy, MAX_SQL_SIZE_GQ );
1437  if ( !rstrcpy( ( char * )&inStrings[inStrIx], tmpStr,
1438  MAX_SQL_SIZE_GQ - inStrIx ) ) {
1439  return USER_STRLEN_TOOLONG;
1440  }
1441  inStrings[inStrIx + ncopy] = '\0';
1442  if ( cllBindVarCount + 1 >= MAX_BIND_VARS ) { // JMC - backport 4848
1444  }
1445 
1446  cllBindVars[cllBindVarCount++] = ( char * )&inStrings[inStrIx];
1447  inStrIx = inStrIx + ncopy + 1;
1448  }
1449  }
1450  }
1451  if ( nput != 2 ) {
1452  return CAT_INVALID_ARGUMENT;
1453  }
1454  return 0;
1455 }
1456 
1457 /*
1458 insert a new where clause using bind-variables
1459  */
1460 int
1461 insertWhere( char *condition, int option ) {
1462  static int bindIx = 0;
1463  static char bindVars[MAX_SQL_SIZE_GQ + 100];
1464  char *cp1, *cpFirstQuote, *cpSecondQuote;
1465  char *cp;
1466  int i;
1467  char *thisBindVar;
1468  char tmpStr[20];
1469  char myCondition[20];
1470  char *condStart;
1471 
1472  if ( option == 1 ) { /* reinitialize */
1473  bindIx = 0;
1474  addInClauseToWhereForIn( condition, option );
1475  return 0;
1476  }
1477 
1478  condStart = condition;
1479  while ( *condStart == ' ' ) {
1480  condStart++;
1481  }
1482 
1483  cp = strstr( condition, "in" );
1484  if ( cp == NULL ) {
1485  cp = strstr( condition, "IN" );
1486  }
1487  if ( cp != NULL && cp == condStart ) {
1488  return addInClauseToWhereForIn( condition, 0 );
1489  }
1490 
1491  cp = strstr( condition, "between" );
1492  if ( cp == NULL ) {
1493  cp = strstr( condition, "BETWEEN" );
1494  }
1495  if ( cp != NULL && cp == condStart ) {
1496  return addBetweenClauseToWhere( condition );
1497  }
1498 
1499  cpFirstQuote = 0;
1500  cpSecondQuote = 0;
1501  for ( cp1 = condition; *cp1 != '\0'; cp1++ ) {
1502  if ( *cp1 == '\'' ) {
1503  if ( cpFirstQuote == 0 ) {
1504  cpFirstQuote = cp1;
1505  }
1506  else {
1507  cpSecondQuote = cp1; /* If embedded 's, skip them; it's OK*/
1508  }
1509  }
1510  }
1511  if ( strcmp( condition, "IS NULL" ) == 0 ) {
1512  if ( !rstrcat( whereSQL, " ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1513  if ( !rstrcat( whereSQL, condition, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1514  if ( !rstrcat( whereSQL, " ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1515  return 0;
1516  }
1517  if ( strcmp( condition, "IS NOT NULL" ) == 0 ) {
1518  if ( !rstrcat( whereSQL, " ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1519  if ( !rstrcat( whereSQL, condition, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1520  if ( !rstrcat( whereSQL, " ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1521  return 0;
1522  }
1523  bindIx++;
1524  thisBindVar = ( char* )&bindVars[bindIx];
1525  if ( cpFirstQuote == 0 || cpSecondQuote == 0 ) {
1526  return CAT_INVALID_ARGUMENT;
1527  }
1528  if ( ( cpSecondQuote - cpFirstQuote ) + bindIx > MAX_SQL_SIZE_GQ + 90 ) {
1529  return CAT_INVALID_ARGUMENT;
1530  }
1531 
1532  for ( cp1 = cpFirstQuote + 1; cp1 < cpSecondQuote; cp1++ ) {
1533  bindVars[bindIx++] = *cp1;
1534  }
1535  bindVars[bindIx++] = '\0';
1536  if ( cllBindVarCount + 1 >= MAX_BIND_VARS ) { // JMC - backport 4848
1538  }
1539 
1540  cllBindVars[cllBindVarCount++] = thisBindVar;
1541 
1542  /* basic legality check on the condition */
1543  if ( ( cpFirstQuote - condition ) > 10 ) {
1544  return CAT_INVALID_ARGUMENT;
1545  }
1546 
1547  tmpStr[0] = ' ';
1548  i = 1;
1549  for ( cp1 = condition;; ) {
1550  tmpStr[i++] = *cp1++;
1551  if ( cp1 == cpFirstQuote ) {
1552  break;
1553  }
1554  }
1555  tmpStr[i] = '\0';
1556  if ( !rstrcpy( myCondition, tmpStr, 20 ) ) {
1557  return USER_STRLEN_TOOLONG;
1558  }
1559 
1560  cp = strstr( myCondition, "begin_of" );
1561  if ( cp != NULL ) {
1562  char tmpStr2[MAX_SQL_SIZE_GQ];
1563  cp1 = whereSQL + strlen( whereSQL ) - 1;
1564  while ( *cp1 != ' ' ) {
1565  cp1--;
1566  }
1567  cp1++;
1568  if ( !rstrcpy( tmpStr2, cp1, MAX_SQL_SIZE_GQ ) ) {
1569  return USER_STRLEN_TOOLONG;
1570  } /*use table/column name just added*/
1571 #if ORA_ICAT
1572  if ( !rstrcat( whereSQL, "=substr(?,1,length(", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1573  if ( !rstrcat( whereSQL, tmpStr2, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1574  if ( !rstrcat( whereSQL, "))", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1575  if ( !rstrcat( whereSQL, " AND length(", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1576 #else
1577  if ( !rstrcat( whereSQL, "=substr(?,1,char_length(", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1578  if ( !rstrcat( whereSQL, tmpStr2, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1579  if ( !rstrcat( whereSQL, "))", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1580  if ( !rstrcat( whereSQL, " AND char_length(", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1581 #endif
1582  if ( !rstrcat( whereSQL, tmpStr2, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1583  if ( !rstrcat( whereSQL, ")>0", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1584  }
1585  else {
1586  cp = strstr( myCondition, "parent_of" );
1587  if ( cp != NULL ) {
1588  /* New version to replace begin_of in a call from
1589  rsObjStat.c, as suggested by Andy Salnikov; add an IN
1590  clause with each of the possible parent collection names;
1591  this is faster, sometimes very much faster. */
1592  cllBindVarCount--; /* undo bind-var as it is not included now */
1593  int status = addInClauseToWhereForParentOf( thisBindVar ); // JMC - backport 4848
1594  if ( status < 0 ) {
1595  return ( status ); // JMC - backport 4848
1596  }
1597  }
1598  else {
1599  tmpStr[i++] = '?';
1600  tmpStr[i++] = ' ';
1601  tmpStr[i++] = '\0';
1602  if ( !rstrcat( whereSQL, tmpStr, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1603  }
1604  }
1605  return checkCondition( myCondition );
1606 }
1607 
1608 /*
1609  Only used if requested by msiAclPolicy (acAclPolicy rule) (which
1610  normally isn't) or if the user is anonymous. This restricts
1611  R_DATA_MAIN anc R_COLL_MAIN info to only users with access.
1612  If client user is the local admin, do not restrict.
1613  */
1614 int
1616  int doCheck = 0;
1617  int ticketAlreadyChecked = 0;
1618 
1620  return 0;
1621  }
1622 
1623  if ( accessControlControlFlag > 1 ) {
1624  doCheck = 1;
1625  }
1626 
1627  if ( doCheck == 0 ) {
1628  if ( strncmp( accessControlUserName, ANONYMOUS_USER, MAX_NAME_LEN ) == 0 ) {
1629  doCheck = 1;
1630  }
1631  }
1632 
1633  if ( cllBindVarCount + 6 >= MAX_BIND_VARS ) {
1634  /* too close, should normally have plenty of slots */
1636  }
1637 
1638  /* First, in all cases (non-admin), check on ticket_string
1639  and, if present, restrict to the owner */
1640  if ( strstr( selectSQL, "ticket_string" ) != NULL &&
1641  strstr( selectSQL, "R_TICKET_MAIN" ) != NULL ) {
1642  if ( strlen( whereSQL ) > 6 ) {
1643  if ( !rstrcat( whereSQL, " AND ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1644  }
1647  if ( !rstrcat( whereSQL, "R_TICKET_MAIN.user_id in (select user_id from R_USER_MAIN UM where UM.user_name = ? AND UM.zone_name=?)", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1648  }
1649 
1650  if ( doCheck == 0 ) {
1651  return 0;
1652  }
1653 
1654  if ( sessionTicket[0] == '\0' ) {
1655  /* Normal access control */
1656 
1657  if ( strstr( selectSQL, "R_DATA_MAIN" ) != NULL ||
1658  strstr( whereSQL, "R_DATA_MAIN" ) != NULL ) {
1659  if ( strlen( whereSQL ) > 6 ) {
1660  if ( !rstrcat( whereSQL, " AND ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1661  }
1662 
1665  if ( !rstrcat( whereSQL, "R_DATA_MAIN.data_id in (select object_id from R_OBJT_ACCESS OA, R_USER_GROUP UG, R_USER_MAIN UM, R_TOKN_MAIN TM where UM.user_name=? and UM.zone_name=? and UM.user_type_name!='rodsgroup' and UM.user_id = UG.user_id and UG.group_user_id = OA.user_id and OA.object_id = R_DATA_MAIN.data_id and OA.access_type_id >= TM.token_id and TM.token_namespace ='access_type' and TM.token_name = 'read object')", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1666  }
1667 
1668  if ( strstr( selectSQL, "R_COLL_MAIN" ) != NULL ||
1669  strstr( whereSQL, "R_COLL_MAIN" ) != NULL ) {
1670  if ( strlen( whereSQL ) > 6 ) {
1671  if ( !rstrcat( whereSQL, " AND ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1672  }
1673 
1676  if ( !rstrcat( whereSQL, "R_COLL_MAIN.coll_id in (select object_id from R_OBJT_ACCESS OA, R_USER_GROUP UG, R_USER_MAIN UM, R_TOKN_MAIN TM where UM.user_name=? and UM.zone_name=? and UM.user_type_name!='rodsgroup' and UM.user_id = UG.user_id and UG.group_user_id = OA.user_id and OA.object_id = R_COLL_MAIN.coll_id and OA.access_type_id >= TM.token_id and TM.token_namespace ='access_type' and TM.token_name = 'read object')", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1677  }
1678  }
1679  else {
1680  /* Ticket-based access control */
1681 
1682  if ( strstr( selectSQL, "R_DATA_MAIN" ) != NULL ||
1683  strstr( whereSQL, "R_DATA_MAIN" ) != NULL ) {
1684  if ( strlen( whereSQL ) > 6 ) {
1685  if ( !rstrcat( whereSQL, " AND ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1686  }
1687 
1691  if ( !rstrcat( whereSQL, "( R_DATA_MAIN.data_id in (select object_id from R_TICKET_MAIN TICK where TICK.ticket_string=?) OR R_COLL_MAIN.coll_id in (select object_id from R_TICKET_MAIN TICK where TICK.ticket_string=?) OR R_COLL_MAIN.coll_name LIKE (select (coll_name || '%') from R_COLL_MAIN where coll_id in (select object_id from R_TICKET_MAIN TICK where TICK.ticket_string=?)))", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1692  ticketAlreadyChecked = 1;
1693  }
1694 
1695  if ( !ticketAlreadyChecked ) {
1696  if ( strstr( selectSQL, "R_COLL_MAIN" ) != NULL ||
1697  strstr( whereSQL, "R_COLL_MAIN" ) != NULL ) {
1698  if ( strlen( whereSQL ) > 6 ) {
1699  if ( !rstrcat( whereSQL, " AND ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1700  }
1701 
1704  if ( !rstrcat( whereSQL, "( R_COLL_MAIN.coll_id in (select object_id from R_TICKET_MAIN TICK where TICK.ticket_string=?) OR R_COLL_MAIN.coll_name LIKE (select (coll_name || '%') from R_COLL_MAIN where coll_id in (select object_id from R_TICKET_MAIN TICK where TICK.ticket_string=?)))", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
1705  }
1706  }
1707  }
1708 
1709  return 0;
1710 }
1711 
1712 /*
1713  Return the columns returned via the generateSpecialQuery's query.
1714  */
1715 int specialQueryIx( int ix ) {
1716  if ( ix == 0 ) {
1717  return COL_QUOTA_USER_ID;
1718  }
1719  if ( ix == 1 ) {
1720  return COL_R_RESC_NAME;
1721  }
1722  if ( ix == 2 ) {
1723  return COL_QUOTA_LIMIT;
1724  }
1725  if ( ix == 3 ) {
1726  return COL_QUOTA_OVER;
1727  }
1728  if ( ix == 4 ) {
1729  return COL_QUOTA_RESC_ID;
1730  }
1731  return 0;
1732 }
1733 
1734 /*
1735  This is used for the QUOTA_QUERY option where a specific query is
1736  needed for efficiency, handling all the quota types in a single query
1737  (the group and individual quotas, per-resource and total-usage).
1738  I decided to make this part of General-Query, since it is so similar but
1739  it is really a specific-query (as an option to general-query).
1740 
1741  The caller specifies a user (COL_USER_NAME) and optionally a resource
1742  (COL_R_RESC_NAME). Rows are returned with the quotas that apply,
1743  most severe (most over or closest to going over) first, if any. For
1744  global-usage quotas, the returned RESC_ID is 0. If the user is a
1745  member of a group with a quota (per-resource or total-usage) a row is
1746  returned for that quota too. All in the appropriate order.
1747  */
1748 int
1749 generateSpecialQuery( genQueryInp_t genQueryInp, char *resultingSQL ) {
1750  static char rescName[LONG_NAME_LEN];
1751  static char userName[NAME_LEN] = "";
1752  static char userZone[NAME_LEN] = "";
1753 
1754  char quotaQuery1[] = "( select distinct QM.user_id, RM.resc_name, QM.quota_limit, QM.quota_over, QM.resc_id from R_QUOTA_MAIN QM, R_RESC_MAIN RM, R_USER_GROUP UG, R_USER_MAIN UM2 where QM.resc_id = RM.resc_id AND (QM.user_id = UG.group_user_id and UM2.user_name = ? and UM2.zone_name = ? and UG.user_id = UM2.user_id )) UNION ( select distinct QM.user_id, RM.resc_name, QM.quota_limit, QM.quota_over, QM.resc_id from R_QUOTA_MAIN QM, R_USER_GROUP UG, R_USER_MAIN UM2, R_RESC_MAIN RM where QM.resc_id = '0' AND (QM.user_id = UG.group_user_id and UM2.user_name = ? and UM2.zone_name = ? and UG.user_id = UM2.user_id)) UNION ( select distinct QM.user_id, RM.resc_name, QM.quota_limit, QM.quota_over, QM.resc_id from R_QUOTA_MAIN QM, R_USER_MAIN UM, R_RESC_MAIN RM WHERE (QM.resc_id = RM.resc_id or QM.resc_id = '0') AND (QM.user_id = UM.user_id and UM.user_name = ? and UM.zone_name = ? )) order by quota_over DESC";
1755 
1756  char quotaQuery2[] = "( select distinct QM.user_id, RM.resc_name, QM.quota_limit, QM.quota_over, QM.resc_id from R_QUOTA_MAIN QM, R_RESC_MAIN RM, R_USER_GROUP UG, R_USER_MAIN UM2 where QM.resc_id = RM.resc_id AND RM.resc_name = ? AND (QM.user_id = UG.group_user_id and UM2.user_name = ? and UM2.zone_name = ? and UG.user_id = UM2.user_id )) UNION ( select distinct QM.user_id, RM.resc_name, QM.quota_limit, QM.quota_over, QM.resc_id from R_QUOTA_MAIN QM, R_USER_GROUP UG, R_USER_MAIN UM2, R_RESC_MAIN RM where QM.resc_id = '0' AND RM.resc_name = ? AND (QM.user_id = UG.group_user_id and UM2.user_name = ? and UM2.zone_name = ? and UG.user_id = UM2.user_id)) UNION ( select distinct QM.user_id, RM.resc_name, QM.quota_limit, QM.quota_over, QM.resc_id from R_QUOTA_MAIN QM, R_USER_MAIN UM, R_RESC_MAIN RM WHERE (QM.resc_id = RM.resc_id or QM.resc_id = '0') AND RM.resc_name = ? AND (QM.user_id = UM.user_id and UM.user_name = ? and UM.zone_name = ? )) order by quota_over DESC";
1757 
1758  int i, valid = 0;
1759  int cllCounter = cllBindVarCount;
1760 
1761  for ( i = 0; i < genQueryInp.sqlCondInp.len; i++ ) {
1762  if ( genQueryInp.sqlCondInp.inx[i] == COL_USER_NAME ) {
1763  int status = parseUserName( genQueryInp.sqlCondInp.value[i], userName,
1764  userZone );
1765  if ( status ) {
1766  rodsLog( LOG_ERROR, "parseUserName failed in generateSpecialQuery on %s with status %d.",
1767  genQueryInp.sqlCondInp.value[i], status );
1768  return status;
1769  }
1770  if ( userZone[0] == '\0' ) {
1771  std::string zoneName;
1772  if ( !chlGetLocalZone( zoneName ) ) {
1773 
1774  }
1775 
1776  snprintf( userZone, sizeof( userZone ), "%s", zoneName.c_str() );
1777  rodsLog( LOG_ERROR, "userZone1=:%s:\n", userZone );
1778  }
1779  rodsLog( LOG_DEBUG, "spQuery(1) userZone2=:%s:\n", userZone );
1780  rodsLog( LOG_DEBUG, "spQuery(1) userName=:%s:\n", userName );
1781  rodsLog( LOG_DEBUG, "spQuery(1) in=:%s:\n",
1782  genQueryInp.sqlCondInp.value[i] );
1783  cllBindVars[cllBindVarCount++] = userName;
1784  cllBindVars[cllBindVarCount++] = userZone;
1785  cllBindVars[cllBindVarCount++] = userName;
1786  cllBindVars[cllBindVarCount++] = userZone;
1787  cllBindVars[cllBindVarCount++] = userName;
1788  cllBindVars[cllBindVarCount++] = userZone;
1789  strncpy( resultingSQL, quotaQuery1, MAX_SQL_SIZE_GQ );
1790  valid = 1;
1791  }
1792  }
1793  if ( valid == 0 ) {
1794  return CAT_INVALID_ARGUMENT;
1795  }
1796  for ( i = 0; i < genQueryInp.sqlCondInp.len; i++ ) {
1797  if ( genQueryInp.sqlCondInp.inx[i] == COL_R_RESC_NAME ) {
1798  rodsLog( LOG_DEBUG, "spQuery(2) userZone2=:%s:\n", userZone );
1799  rodsLog( LOG_DEBUG, "spQuery(2) userName=:%s:\n", userName );
1800  rodsLog( LOG_DEBUG, "spQuery(2) in=:%s:\n",
1801  genQueryInp.sqlCondInp.value[i] );
1802  snprintf( rescName, sizeof( rescName ), "%s", genQueryInp.sqlCondInp.value[i] );
1803  cllBindVars[cllCounter++] = rescName;
1804  cllBindVars[cllCounter++] = userName;
1805  cllBindVars[cllCounter++] = userZone;
1806  cllBindVars[cllCounter++] = rescName;
1807  cllBindVars[cllCounter++] = userName;
1808  cllBindVars[cllCounter++] = userZone;
1809  cllBindVars[cllCounter++] = rescName;
1810  cllBindVars[cllCounter++] = userName;
1811  cllBindVars[cllCounter++] = userZone;
1812 
1813  strncpy( resultingSQL, quotaQuery2, MAX_SQL_SIZE_GQ );
1814  cllBindVarCount = cllCounter;
1815  }
1816  }
1817  return 0;
1818 }
1819 
1820 /*
1821 Called by chlGenQuery to generate the SQL.
1822 */
1823 int
1824 generateSQL( genQueryInp_t genQueryInp, char *resultingSQL,
1825  char *resultingCountSQL ) {
1826  int i, table, startingTable = 0;
1827  int keepVal;
1828  char *condition;
1829  int status;
1830  int useGroupBy;
1831  int N_col_meta_data_attr_name = 0;
1832  int N_col_meta_coll_attr_name = 0;
1833  int N_col_meta_user_attr_name = 0;
1834  int N_col_meta_resc_attr_name = 0;
1835  int N_col_meta_resc_group_attr_name = 0;
1836 
1837  char combinedSQL[MAX_SQL_SIZE_GQ];
1838 #if ORA_ICAT
1839  char countSQL[MAX_SQL_SIZE_GQ];
1840 #else
1841  static char offsetStr[20];
1842 #endif
1843 
1844  if ( firstCall ) {
1845  icatGeneralQuerySetup(); /* initialize */
1846  }
1847  firstCall = 0;
1848 
1849  nToFind = 0;
1850  for ( i = 0; i < nTables; i++ ) {
1851  Tables[i].flag = 0;
1852  }
1853 
1854  insertWhere( "", 1 ); /* initialize */
1855 
1856  if ( genQueryInp.options & NO_DISTINCT ) {
1857  if ( !rstrcpy( selectSQL, "select ", MAX_SQL_SIZE_GQ ) ) {
1858  return USER_STRLEN_TOOLONG;
1859  }
1860  }
1861  else {
1862  if ( !rstrcpy( selectSQL, "select distinct ", MAX_SQL_SIZE_GQ ) ) {
1863  return USER_STRLEN_TOOLONG;
1864  }
1865  }
1866  selectSQLInitFlag = 1; /* selectSQL is currently initialized (no Columns) */
1867  doUpperCase = 0;
1868  if ( genQueryInp.options & UPPER_CASE_WHERE ) {
1869  doUpperCase = 1;
1870  }
1871 
1872  if ( !rstrcpy( fromSQL, "from ", MAX_SQL_SIZE_GQ ) ) {
1873  return USER_STRLEN_TOOLONG;
1874  }
1875  fromCount = 0;
1876  if ( !rstrcpy( whereSQL, "where ", MAX_SQL_SIZE_GQ ) ) {
1877  return USER_STRLEN_TOOLONG;
1878  }
1879  if ( !rstrcpy( groupBySQL, "group by ", MAX_SQL_SIZE_GQ ) ) {
1880  return USER_STRLEN_TOOLONG;
1881  }
1882  mightNeedGroupBy = 0;
1883 
1884  tableAbbrevs = 'a'; /* reset */
1885 
1886  for ( i = 0; i < genQueryInp.selectInp.len; i++ ) {
1887  table = setTable( genQueryInp.selectInp.inx[i], 1,
1888  genQueryInp.selectInp.value[i] & 0xf, 0 );
1889  if ( table < 0 ) {
1890  std::cerr << irods::stacktrace().dump(); // XXXX - JMC
1891  rodsLog( LOG_ERROR, "Table for column %d not found\n",
1892  genQueryInp.selectInp.inx[i] );
1893  return CAT_UNKNOWN_TABLE;
1894  }
1895 
1896  if ( genQueryInp.selectInp.inx[i] >= COL_AUDIT_RANGE_START &&
1897  genQueryInp.selectInp.inx[i] <= COL_AUDIT_RANGE_END ) {
1899  return CAT_NO_ACCESS_PERMISSION;
1900  }
1901  }
1902 
1903  if ( Tables[table].cycler < 1 || startingTable == 0 ) {
1904  startingTable = table; /* start with a non-cycler, if possible */
1905  }
1906  }
1907 
1908  handleCompoundCondition( "", -1 ); /* reinitialize */
1909  for ( i = 0; i < genQueryInp.sqlCondInp.len; i++ ) {
1910  int prevWhereLen;
1911  int castOption;
1912  char *cptr;
1913 
1914  prevWhereLen = strlen( whereSQL );
1915  if ( genQueryInp.sqlCondInp.inx[i] == COL_META_DATA_ATTR_NAME ) {
1916  N_col_meta_data_attr_name++;
1917  }
1918  if ( genQueryInp.sqlCondInp.inx[i] == COL_META_COLL_ATTR_NAME ) {
1919  N_col_meta_coll_attr_name++;
1920  }
1921  if ( genQueryInp.sqlCondInp.inx[i] == COL_META_USER_ATTR_NAME ) {
1922  N_col_meta_user_attr_name++;
1923  }
1924  if ( genQueryInp.sqlCondInp.inx[i] == COL_META_RESC_ATTR_NAME ) {
1925  N_col_meta_resc_attr_name++;
1926  }
1927  if ( genQueryInp.sqlCondInp.inx[i] == COL_META_RESC_GROUP_ATTR_NAME ) {
1928  N_col_meta_resc_group_attr_name++;
1929  }
1930  /*
1931  Using an input condition, determine if the associated column is being
1932  requested to be cast as an int. That is, if the input is n< n> or n=.
1933  */
1934  castOption = 0;
1935  cptr = genQueryInp.sqlCondInp.value[i];
1936  while ( *cptr == ' ' ) {
1937  cptr++;
1938  }
1939  if ( ( *cptr == 'n' && *( cptr + 1 ) == '<' ) ||
1940  ( *cptr == 'n' && *( cptr + 1 ) == '>' ) ||
1941  ( *cptr == 'n' && *( cptr + 1 ) == '=' ) ) {
1942  castOption = 1;
1943  *cptr = ' '; /* clear the 'n' that was just checked so what
1944  remains is proper SQL */
1945  }
1946  table = setTable( genQueryInp.sqlCondInp.inx[i], 0, 0,
1947  castOption );
1948  if ( table < 0 ) {
1949  std::cerr << irods::stacktrace().dump(); // XXXX - JMC
1950  rodsLog( LOG_ERROR, "Table for column %d not found\n",
1951  genQueryInp.sqlCondInp.inx[i] );
1952  return CAT_UNKNOWN_TABLE;
1953  }
1954  if ( Tables[table].cycler < 1 ) {
1955  startingTable = table; /* start with a non-cycler */
1956  }
1957  condition = genQueryInp.sqlCondInp.value[i];
1958  if ( compoundConditionSpecified( condition ) ) {
1959  status = handleCompoundCondition( condition, prevWhereLen );
1960  if ( status ) {
1961  return status;
1962  }
1963  }
1964  else {
1965  status = insertWhere( condition, 0 );
1966  if ( status ) {
1967  return status;
1968  }
1969  }
1970 
1971  if ( genQueryInp.sqlCondInp.inx[i] >= COL_AUDIT_RANGE_START &&
1972  genQueryInp.sqlCondInp.inx[i] <= COL_AUDIT_RANGE_END ) {
1974  return CAT_NO_ACCESS_PERMISSION;
1975  }
1976  }
1977 
1978  }
1979 
1980  keepVal = tScan( startingTable, -1 );
1981  if ( keepVal != 1 || nToFind != 0 ) {
1982  rodsLog( LOG_ERROR, "error failed to link tables\n" );
1984  }
1985  else {
1986  if ( debug > 1 ) {
1987  printf( "SUCCESS linking tables\n" );
1988  }
1989  }
1990 
1991  if ( N_col_meta_data_attr_name > 1 ) {
1992  /* Make some special changes & additions for multi AVU query - data */
1993  handleMultiDataAVUConditions( N_col_meta_data_attr_name );
1994  }
1995 
1996  if ( N_col_meta_coll_attr_name > 1 ) {
1997  /* Make some special changes & additions for multi AVU query - collections */
1998  handleMultiCollAVUConditions( N_col_meta_coll_attr_name );
1999  }
2000 
2001  if ( N_col_meta_user_attr_name > 1 ) {
2002  /* Not currently handled, return error */
2003  return CAT_INVALID_ARGUMENT;
2004  }
2005  if ( N_col_meta_resc_attr_name > 1 ) {
2006  /* Not currently handled, return error */
2007  return CAT_INVALID_ARGUMENT;
2008  }
2009  if ( N_col_meta_resc_group_attr_name > 1 ) {
2010  /* Not currently handled, return error */
2011  return CAT_INVALID_ARGUMENT;
2012  }
2013 
2014  if ( debug ) {
2015  printf( "selectSQL: %s\n", selectSQL );
2016  }
2017  if ( debug ) {
2018  printf( "fromSQL: %s\n", fromSQL );
2019  }
2020  if ( debug ) {
2021  printf( "whereSQL: %s\n", whereSQL );
2022  }
2023  useGroupBy = 0;
2024  if ( mightNeedGroupBy ) {
2025  if ( strlen( groupBySQL ) > 10 ) {
2026  useGroupBy = 1;
2027  }
2028  }
2029  if ( debug && useGroupBy ) {
2030  printf( "groupBySQL: %s\n", groupBySQL );
2031  }
2032 
2033  combinedSQL[0] = '\0';
2034  if ( !rstrcat( combinedSQL, selectSQL, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2035  if ( !rstrcat( combinedSQL, " " , MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2036  if ( !rstrcat( combinedSQL, fromSQL, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2037 
2039 
2040  if ( strlen( whereSQL ) > 6 ) {
2041  if ( !rstrcat( combinedSQL, " " , MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2042  if ( !rstrcat( combinedSQL, whereSQL, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2043  }
2044  if ( useGroupBy ) {
2045  if ( !rstrcat( combinedSQL, " " , MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2046  if ( !rstrcat( combinedSQL, groupBySQL, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2047  }
2048  if ( !rstrcpy( orderBySQL, " order by ", MAX_SQL_SIZE_GQ ) ) {
2049  return USER_STRLEN_TOOLONG;
2050  }
2051  setOrderByUser( genQueryInp );
2052  setOrderBy( genQueryInp, COL_COLL_NAME );
2053  setOrderBy( genQueryInp, COL_DATA_NAME );
2054  setOrderBy( genQueryInp, COL_DATA_REPL_NUM );
2055  if ( strlen( orderBySQL ) > 10 ) {
2056  if ( !rstrcat( combinedSQL, orderBySQL, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2057  }
2058 
2059  if ( genQueryInp.rowOffset > 0 ) {
2060 #if ORA_ICAT
2061  /* For Oracle, it may be possible to do this by surrounding the
2062  select with another select and using rownum or row_number(),
2063  but there are a number of subtle problems/special cases to
2064  deal with. So instead, we handle this elsewhere by getting
2065  and disgarding rows. */
2066 #elif MY_ICAT
2067  /* MySQL/ODBC handles it nicely via just adding limit/offset */
2068  snprintf( offsetStr, sizeof offsetStr, "%d", genQueryInp.rowOffset );
2069  if ( !rstrcat( combinedSQL, " limit ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2070  if ( !rstrcat( combinedSQL, offsetStr, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2071  if ( !rstrcat( combinedSQL, ",18446744073709551615", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2072 #else
2073  /* Postgres/ODBC handles it nicely via just adding offset */
2074  snprintf( offsetStr, sizeof offsetStr, "%d", genQueryInp.rowOffset );
2075  cllBindVars[cllBindVarCount++] = offsetStr;
2076  if ( !rstrcat( combinedSQL, " offset ?", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2077 #endif
2078  }
2079 
2080  if ( debug ) {
2081  printf( "combinedSQL=:%s:\n", combinedSQL );
2082  }
2083  strncpy( resultingSQL, combinedSQL, MAX_SQL_SIZE_GQ );
2084 
2085 #if ORA_ICAT
2086  countSQL[0] = '\0';
2087  if ( !rstrcat( countSQL, "select distinct count(*) ", MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2088  if ( !rstrcat( countSQL, fromSQL, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2089 
2090  if ( strlen( whereSQL ) > 6 ) {
2091  if ( !rstrcat( countSQL, " " , MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2092  if ( !rstrcat( countSQL, whereSQL, MAX_SQL_SIZE_GQ ) ) { return USER_STRLEN_TOOLONG; }
2093  }
2094 
2095  if ( debug ) {
2096  printf( "countSQL=:%s:\n", countSQL );
2097  }
2098  strncpy( resultingCountSQL, countSQL, MAX_SQL_SIZE_GQ );
2099 #endif
2100  return 0;
2101 }
2102 
2103 /*
2104  Perform a check based on the condInput parameters;
2105  Verify that the user has access to the dataObj at the requested level.
2106 
2107  If continueFlag is non-zero this is a continuation (more rows), so if
2108  the dataId is the same, can skip the check to the db.
2109  */
2110 int
2111 checkCondInputAccess( genQueryInp_t genQueryInp, int statementNum,
2112  icatSessionStruct *icss, int continueFlag ) {
2113  int i, nCols;
2114  int userIx = -1, zoneIx = -1, accessIx = -1, dataIx = -1, collIx = -1;
2115  int status;
2116  std::string zoneName;
2117 
2118  static char prevDataId[LONG_NAME_LEN];
2119  static char prevUser[LONG_NAME_LEN];
2120  static char prevAccess[LONG_NAME_LEN];
2121  static int prevStatus;
2122 
2123  if ( getValByKey( &genQueryInp.condInput, ADMIN_KW ) ) {
2124  return 0;
2125  }
2126 
2127  for ( i = 0; i < genQueryInp.condInput.len; i++ ) {
2128  if ( strcmp( genQueryInp.condInput.keyWord[i],
2129  USER_NAME_CLIENT_KW ) == 0 ) {
2130  userIx = i;
2131  }
2132  if ( strcmp( genQueryInp.condInput.keyWord[i],
2133  RODS_ZONE_CLIENT_KW ) == 0 ) {
2134  zoneIx = i;
2135  }
2136  if ( strcmp( genQueryInp.condInput.keyWord[i],
2137  ACCESS_PERMISSION_KW ) == 0 ) {
2138  accessIx = i;
2139  }
2140  if ( strcmp( genQueryInp.condInput.keyWord[i],
2141  TICKET_KW ) == 0 ) {
2142  /* for now, log it but the one used is the session ticket */
2143  rodsLog( LOG_NOTICE, "ticket input, value: %s",
2144  genQueryInp.condInput.value[i] );
2145  }
2146  }
2147  if ( genQueryInp.condInput.len == 1 &&
2148  strcmp( genQueryInp.condInput.keyWord[0], ZONE_KW ) == 0 ) {
2149  return 0;
2150  }
2151 
2152  if ( userIx < 0 || zoneIx < 0 || accessIx < 0 ) {
2153  // this function will get called if any condInput is available. we now have a
2154  // case where this kvp is the only option so consider that a success
2155  char* disable_acl = getValByKey( &genQueryInp.condInput, DISABLE_STRICT_ACL_KW );
2156  if ( disable_acl ) {
2157  return 0;
2158  }
2159  return CAT_INVALID_ARGUMENT;
2160  }
2161 
2162  /* Try to find the dataId and/or collID in the output */
2163  nCols = icss->stmtPtr[statementNum]->numOfCols;
2164  for ( i = 0; i < nCols; i++ ) {
2165  if ( strcmp( icss->stmtPtr[statementNum]->resultColName[i], "data_id" ) == 0 ) {
2166  dataIx = i;
2167  }
2168  /* With Oracle the column names are in upper case: */
2169  if ( strcmp( icss->stmtPtr[statementNum]->resultColName[i], "DATA_ID" ) == 0 ) {
2170  dataIx = i;
2171  }
2172  if ( strcmp( icss->stmtPtr[statementNum]->resultColName[i], "coll_id" ) == 0 ) {
2173  collIx = i;
2174  }
2175  /* With Oracle the column names are in upper case: */
2176  if ( strcmp( icss->stmtPtr[statementNum]->resultColName[i], "COLL_ID" ) == 0 ) {
2177  collIx = i;
2178  }
2179  }
2180  if ( dataIx < 0 && collIx < 0 ) {
2181  return CAT_INVALID_ARGUMENT;
2182  }
2183 
2184  if ( dataIx >= 0 ) {
2185  if ( continueFlag == 1 ) {
2186  if ( strcmp( prevDataId,
2187  icss->stmtPtr[statementNum]->resultValue[dataIx] ) == 0 ) {
2188  if ( strcmp( prevUser, genQueryInp.condInput.value[userIx] ) == 0 ) {
2189  if ( strcmp( prevAccess,
2190  genQueryInp.condInput.value[accessIx] ) == 0 ) {
2191  return prevStatus;
2192  }
2193  }
2194  }
2195  }
2196 
2197  snprintf( prevDataId, sizeof( prevDataId ), "%s", icss->stmtPtr[statementNum]->resultValue[dataIx] );
2198  snprintf( prevUser, sizeof( prevUser ), "%s", genQueryInp.condInput.value[userIx] );
2199  snprintf( prevAccess, sizeof( prevAccess ), "%s", genQueryInp.condInput.value[accessIx] );
2200  prevStatus = 0;
2201 
2202  if ( strlen( genQueryInp.condInput.value[zoneIx] ) == 0 ) {
2203  if ( !chlGetLocalZone( zoneName ) ) {
2204  }
2205  }
2206  else {
2207  zoneName = genQueryInp.condInput.value[zoneIx];
2208  }
2209 
2211  icss->stmtPtr[statementNum]->resultValue[dataIx],
2212  genQueryInp.condInput.value[userIx],
2213  ( char* )zoneName.c_str(),
2214  genQueryInp.condInput.value[accessIx],
2215  /* sessionTicket, accessControlHost, icss); */
2217  prevStatus = status;
2218  return status;
2219  }
2220 
2221  if ( collIx >= 0 ) {
2222  if ( strlen( genQueryInp.condInput.value[zoneIx] ) == 0 ) {
2223  if ( !chlGetLocalZone( zoneName ) ) {
2224  }
2225  }
2226  else {
2227  zoneName = genQueryInp.condInput.value[zoneIx];
2228  }
2230  icss->stmtPtr[statementNum]->resultValue[collIx],
2231  genQueryInp.condInput.value[userIx],
2232  ( char* )zoneName.c_str(),
2233  genQueryInp.condInput.value[accessIx], icss );
2234  }
2235  return 0;
2236 }
2237 
2238 /* Save some pre-provided parameters if msiAclPolicy is STRICT.
2239  Called with user == NULL to set the controlFlag, else with the
2240  user info.
2241  */
2242 
2244  const char *user,
2245  const char *zone,
2246  const char *host,
2247  int priv,
2248  int controlFlag ) {
2249  if ( user != NULL ) {
2250  if ( !rstrcpy( accessControlUserName, user, MAX_NAME_LEN ) ) {
2251  return USER_STRLEN_TOOLONG;
2252  }
2253  if ( !rstrcpy( accessControlZone, zone, MAX_NAME_LEN ) ) {
2254  return USER_STRLEN_TOOLONG;
2255  }
2256 // if(!rstrcpy(accessControlHost, host, MAX_NAME_LEN);
2257  accessControlPriv = priv;
2258  }
2259 
2260  // =-=-=-=-=-=-=-
2261  // add the >= 0 to allow for repave of strict acl due to
2262  // issue with file create vs file open in rsDataObjCreate
2263  int old_flag = accessControlControlFlag;
2264  if ( controlFlag >= 0 ) {
2265  /*
2266  If the caller is making this STRICT, then allow the change as
2267  this will be an initial acAclPolicy call which is setup in
2268  core.re. But don't let users override this admin setting
2269  via their own calls to the msiAclPolicy; once it is STRICT,
2270  it stays strict.
2271  */
2272  accessControlControlFlag = controlFlag;
2273  }
2274 
2275  return old_flag;
2276 }
2277 
2279  const char* ticket,
2280  const char* clientAddr ) {
2281  if ( !rstrcpy( sessionTicket, ticket, sizeof( sessionTicket ) ) ) {
2282  return USER_STRLEN_TOOLONG;
2283  }
2284  if ( !rstrcpy( sessionClientAddr, clientAddr, sizeof( sessionClientAddr ) ) ) {
2285  return USER_STRLEN_TOOLONG;
2286  }
2287  rodsLog( LOG_NOTICE, "session ticket setup, value: %s", ticket );
2288  return 0;
2289 }
2290 
2291 
2292 /* General Query */
2294  genQueryInp_t genQueryInp,
2295  genQueryOut_t* result ) {
2296  int i, j, k;
2297  int needToGetNextRow;
2298 
2299  char combinedSQL[MAX_SQL_SIZE_GQ];
2300  char countSQL[MAX_SQL_SIZE_GQ]; /* For Oracle, sql to get the count */
2301 
2302  int status, statementNum = UNINITIALIZED_STATEMENT_NUMBER;
2303  int numOfCols;
2304  int attriTextLen;
2305  int totalLen;
2306  int maxColSize;
2307  int currentMaxColSize;
2308  char *tResult, *tResult2;
2309  static int recursiveCall = 0;
2310 
2311  if ( logSQLGenQuery ) {
2312  rodsLog( LOG_SQL, "chlGenQuery" );
2313  }
2314 
2315  icatSessionStruct *icss = 0;
2316 
2317  result->attriCnt = 0;
2318  result->rowCnt = 0;
2319  result->totalRowCount = 0;
2320 
2321  currentMaxColSize = 0;
2322 
2323  status = chlGetRcs( &icss );
2324  if ( status < 0 || icss == NULL ) {
2325  return CAT_NOT_OPEN;
2326  }
2327  if ( debug ) {
2328  printf( "icss=%ju\n", ( uintmax_t )icss );
2329  }
2330 
2331  if ( genQueryInp.continueInx == 0 ) {
2332  if ( genQueryInp.options & QUOTA_QUERY ) {
2333  countSQL[0] = '\0';
2334  status = generateSpecialQuery( genQueryInp, combinedSQL );
2335  }
2336  else {
2337  status = generateSQL( genQueryInp, combinedSQL, countSQL );
2338  }
2339  if ( status != 0 ) {
2340  return status;
2341  }
2342  if ( logSQLGenQuery ) {
2343  if ( genQueryInp.rowOffset == 0 ) {
2344  rodsLog( LOG_SQL, "chlGenQuery SQL 1" );
2345  }
2346  else {
2347  rodsLog( LOG_SQL, "chlGenQuery SQL 2" );
2348  }
2349  }
2350 
2351  if ( genQueryInp.options & RETURN_TOTAL_ROW_COUNT ) {
2352  /* For Oracle, done just below, for Postgres a little later */
2353  if ( logSQLGenQuery ) {
2354  rodsLog( LOG_SQL, "chlGenQuery SQL 3" );
2355  }
2356  }
2357 
2358 #if ORA_ICAT
2359  if ( genQueryInp.options & RETURN_TOTAL_ROW_COUNT ) {
2360  int cllBindVarCountSave;
2361  rodsLong_t iVal;
2362  cllBindVarCountSave = cllBindVarCount;
2363  status = cmlGetIntegerValueFromSqlV3( countSQL, &iVal,
2364  icss );
2365  if ( status < 0 ) {
2366  if ( status != CAT_NO_ROWS_FOUND ) {
2368  "chlGenQuery cmlGetIntegerValueFromSqlV3 failure %d",
2369  status );
2370  }
2371  return status;
2372  }
2373  if ( iVal >= 0 ) {
2374  result->totalRowCount = iVal;
2375  }
2376  cllBindVarCount = cllBindVarCountSave;
2377  }
2378 #endif
2379 
2380  status = cmlGetFirstRowFromSql( combinedSQL, &statementNum,
2381  genQueryInp.rowOffset, icss );
2382  if ( status < 0 ) {
2383  if ( status != CAT_NO_ROWS_FOUND ) {
2385  "chlGenQuery cmlGetFirstRowFromSql failure %d",
2386  status );
2387  }
2388 #if ORA_ICAT
2389 #else
2390  else {
2391  int saveStatus;
2392  if ( genQueryInp.options & RETURN_TOTAL_ROW_COUNT &&
2393  genQueryInp.rowOffset > 0 ) {
2394  /* For Postgres in this case, need to query again to determine total rows */
2395  saveStatus = status;
2396  recursiveCall = 1;
2397  genQueryInp.rowOffset = 0;
2398  chlGenQuery( genQueryInp, result );
2399  return saveStatus;
2400  }
2401  }
2402 #endif
2403  return status;
2404  }
2405 
2406 #if ORA_ICAT
2407  recursiveCall = 0; /* avoid warning */
2408 #else
2409  if ( genQueryInp.options & RETURN_TOTAL_ROW_COUNT ) {
2410  i = cllGetRowCount( icss, statementNum );
2411  if ( i >= 0 ) {
2412  result->totalRowCount = i + genQueryInp.rowOffset;
2413  }
2414  if ( recursiveCall == 1 ) {
2415  recursiveCall = 0;
2416  return status;
2417  }
2418  }
2419 #endif
2420 
2421  if ( genQueryInp.condInput.len > 0 ) {
2422  status = checkCondInputAccess( genQueryInp, statementNum, icss, 0 );
2423  if ( status != 0 ) {
2424  result->continueInx = statementNum+1; // provide index to close statement
2425  return status;
2426  }
2427  }
2428  if ( debug ) {
2429  printf( "statement number =%d\n", statementNum );
2430  }
2431  needToGetNextRow = 0;
2432  }
2433  else {
2434 
2435  statementNum = genQueryInp.continueInx - 1;
2436  needToGetNextRow = 1;
2437  if ( genQueryInp.maxRows <= 0 ) { /* caller is closing out the query */
2438  status = cmlFreeStatement( statementNum, icss );
2439  return status;
2440  }
2441  }
2442  for ( i = 0; i < genQueryInp.maxRows; i++ ) {
2443  if ( needToGetNextRow ) {
2444  status = cmlGetNextRowFromStatement( statementNum, icss );
2445  if ( status == CAT_NO_ROWS_FOUND ) {
2446  cmlFreeStatement( statementNum, icss );
2447  result->continueInx = 0;
2448  if ( result->rowCnt == 0 ) {
2449  return status;
2450  } /* NO ROWS; in this
2451  case a continuation call is finding no more rows */
2452  return 0;
2453  }
2454  if ( status < 0 ) {
2455  return status;
2456  }
2457  if ( genQueryInp.condInput.len > 0 ) {
2458  status = checkCondInputAccess( genQueryInp, statementNum, icss, 1 );
2459  if ( status != 0 ) {
2460  return status;
2461  }
2462  }
2463  }
2464  needToGetNextRow = 1;
2465 
2466  result->rowCnt++;
2467  if ( debug ) {
2468  printf( "result->rowCnt=%d\n", result->rowCnt );
2469  }
2470  numOfCols = icss->stmtPtr[statementNum]->numOfCols;
2471  if ( debug ) {
2472  printf( "numOfCols=%d\n", numOfCols );
2473  }
2474  result->attriCnt = numOfCols;
2475  result->continueInx = statementNum + 1;
2476 
2477  maxColSize = 0;
2478 
2479  for ( k = 0; k < numOfCols; k++ ) {
2480  j = strlen( icss->stmtPtr[statementNum]->resultValue[k] );
2481  if ( maxColSize <= j ) {
2482  maxColSize = j;
2483  }
2484  }
2485  maxColSize++; /* for the null termination */
2486  if ( maxColSize < MINIMUM_COL_SIZE ) {
2487  maxColSize = MINIMUM_COL_SIZE; /* make it a reasonable size */
2488  }
2489  if ( debug ) {
2490  printf( "maxColSize=%d\n", maxColSize );
2491  }
2492 
2493  if ( i == 0 ) { /* first time thru, allocate and initialize */
2494  attriTextLen = numOfCols * maxColSize;
2495  if ( debug ) {
2496  printf( "attriTextLen=%d\n", attriTextLen );
2497  }
2498  totalLen = attriTextLen * genQueryInp.maxRows;
2499  for ( j = 0; j < numOfCols; j++ ) {
2500  tResult = ( char* )malloc( totalLen );
2501  if ( tResult == NULL ) {
2502  return SYS_MALLOC_ERR;
2503  }
2504  memset( tResult, 0, totalLen );
2505  if ( genQueryInp.options & QUOTA_QUERY ) {
2506  result->sqlResult[j].attriInx = specialQueryIx( j );
2507  }
2508  else {
2509  result->sqlResult[j].attriInx = genQueryInp.selectInp.inx[j];
2510  }
2511  result->sqlResult[j].len = maxColSize;
2512  result->sqlResult[j].value = tResult;
2513  }
2514  currentMaxColSize = maxColSize;
2515  }
2516 
2517 
2518  /* Check to see if the current row has a max column size that
2519  is larger than what we've been using so far. If so, allocate
2520  new result strings, copy each row value over, and free the
2521  old one. */
2522  if ( maxColSize > currentMaxColSize ) {
2523  maxColSize += MINIMUM_COL_SIZE; // bump it up to try to avoid some multiple resizes
2524  if ( debug ) printf( "Bumping %d to %d\n",
2525  currentMaxColSize, maxColSize );
2526  attriTextLen = numOfCols * maxColSize;
2527  if ( debug ) {
2528  printf( "attriTextLen=%d\n", attriTextLen );
2529  }
2530  totalLen = attriTextLen * genQueryInp.maxRows;
2531  for ( j = 0; j < numOfCols; j++ ) {
2532  char *cp1, *cp2;
2533  int k;
2534  tResult = ( char* )malloc( totalLen );
2535  if ( tResult == NULL ) {
2536  return SYS_MALLOC_ERR;
2537  }
2538  memset( tResult, 0, totalLen );
2539  cp1 = result->sqlResult[j].value;
2540  cp2 = tResult;
2541  for ( k = 0; k < result->rowCnt; k++ ) {
2542  strncpy( cp2, cp1, result->sqlResult[j].len );
2543  cp1 += result->sqlResult[j].len;
2544  cp2 += maxColSize;
2545  }
2546  free( result->sqlResult[j].value );
2547  result->sqlResult[j].len = maxColSize;
2548  result->sqlResult[j].value = tResult;
2549  }
2550  currentMaxColSize = maxColSize;
2551  }
2552 
2553  /* Store the current row values into the appropriate spots in
2554  the attribute string */
2555  for ( j = 0; j < numOfCols; j++ ) {
2556  tResult2 = result->sqlResult[j].value; // ptr to value str
2557  tResult2 += currentMaxColSize * ( result->rowCnt - 1 ); // skip forward for this row
2558  strncpy( tResult2, icss->stmtPtr[statementNum]->resultValue[j],
2559  currentMaxColSize ); // copy in the value text
2560  }
2561 
2562  }
2563 
2564  result->continueInx = statementNum + 1; // the statement number but always >0
2565  if ( genQueryInp.options & AUTO_CLOSE ) {
2566  int status2;
2567  result->continueInx = -1; // Indicate more rows might have been available
2568  status2 = cmlFreeStatement( statementNum, icss );
2569  return status2;
2570  }
2571  return 0;
2572 
2573 }
2574 
2575 int
2577  logSQLGenQuery = mode;
2578  return 0;
2579 }
rodsLog
void rodsLog(int level, const char *formatStr,...)
Definition: rodsLog.cpp:86
getValByKey
char * getValByKey(const keyValPair_t *condInput, const char *keyWord)
Definition: rcMisc.cpp:675
NULL
#define NULL
Definition: rodsDef.h:70
rstrcat
char * rstrcat(char *dest, const char *src, int maxLen)
Definition: stringOpr.cpp:75
irods.pyparsing.tableName
def tableName
Definition: pyparsing.py:3817
irods::stacktrace::dump
const std::string & dump() const
Definition: irods_stacktrace.cpp:55
COL_R_RESC_NAME
#define COL_R_RESC_NAME
Definition: rodsGenQuery.h:144
COL_DATA_REPL_NUM
#define COL_DATA_REPL_NUM
Definition: rodsGenQuery.h:166
irods.pyparsing.empty
empty
Definition: pyparsing.py:3430
GenQueryOut::totalRowCount
int totalRowCount
Definition: rodsGenQuery.h:71
icatStmtStrct::resultColName
char * resultColName[30]
Definition: icatStructs.hpp:18
CAT_BIND_VARIABLE_LIMIT_EXCEEDED
@ CAT_BIND_VARIABLE_LIMIT_EXCEEDED
Definition: rodsErrorTable.h:462
irods.pyparsing.columnName
def columnName
Definition: pyparsing.py:3815
GenQueryInp::continueInx
int continueInx
Definition: rodsGenQuery.h:28
accessControlUserName
char accessControlUserName[(1024+64)]
Definition: general_query.cpp:62
SELECT_COUNT
#define SELECT_COUNT
Definition: rodsGenQuery.h:106
CAT_NO_ACCESS_PERMISSION
@ CAT_NO_ACCESS_PERMISSION
Definition: rodsErrorTable.h:433
setOrderBy
void setOrderBy(genQueryInp_t genQueryInp, int column)
Definition: general_query.cpp:1076
specialQueryIx
int specialQueryIx(int ix)
Definition: general_query.cpp:1715
findCycles
int findCycles(int startTable)
Definition: general_query.cpp:589
sessionTicket
char sessionTicket[(1024+64)]
Definition: general_query.cpp:66
SYS_MALLOC_ERR
@ SYS_MALLOC_ERR
Definition: rodsErrorTable.h:84
SqlResult::attriInx
int attriInx
Definition: rodsGenQuery.h:62
chl_gen_query_access_control_setup_impl
int chl_gen_query_access_control_setup_impl(const char *user, const char *zone, const char *host, int priv, int controlFlag)
Definition: general_query.cpp:2243
tTables::tableAbbrev
char tableAbbrev[2]
Definition: general_query.cpp:83
sTest2
int sTest2(int i1, int i2, int i3)
Definition: general_query.cpp:488
tablePresent
int tablePresent(char *table, char *sqlText)
Definition: general_query.cpp:255
handleCompoundCondition
int handleCompoundCondition(char *condition, int prevWhereLen)
Definition: general_query.cpp:963
tScan
int tScan(int table, int link)
Definition: general_query.cpp:332
tTables::cycler
int cycler
Definition: general_query.cpp:81
USER_NAME_CLIENT_KW
#define USER_NAME_CLIENT_KW
Definition: rodsKeyWdDef.h:164
logSQLGenQuery
int logSQLGenQuery
Definition: icatHighLevelRoutines.cpp:39
tColumns::columnName
char columnName[64]
Definition: general_query.cpp:90
GenQueryInp
Definition: rodsGenQuery.h:24
SELECT_MAX
#define SELECT_MAX
Definition: rodsGenQuery.h:103
generateSpecialQuery
int generateSpecialQuery(genQueryInp_t genQueryInp, char *resultingSQL)
Definition: general_query.cpp:1749
irods::stacktrace
Definition: irods_stacktrace.hpp:11
AUTO_CLOSE
#define AUTO_CLOSE
Definition: rodsGenQuery.h:89
CAT_NOT_OPEN
@ CAT_NOT_OPEN
Definition: rodsErrorTable.h:439
tCycleChk
int tCycleChk(int table, int link, int thisTreeNum)
Definition: general_query.cpp:519
ACCESS_PERMISSION_KW
#define ACCESS_PERMISSION_KW
Definition: rodsKeyWdDef.h:185
sFklink
int sFklink(const char *table1, const char *table2, const char *connectingSQL)
Definition: general_query.cpp:157
SELECT_AVG
#define SELECT_AVG
Definition: rodsGenQuery.h:105
LONG_NAME_LEN
#define LONG_NAME_LEN
Definition: rodsDef.h:57
fromSQL
char fromSQL[16000]
Definition: general_query.cpp:56
tColumns::tableName
char tableName[64]
Definition: general_query.cpp:91
cllBindVarCount
int cllBindVarCount
Definition: low_level_odbc.cpp:47
InxIvalPair::len
int len
Definition: objInfo.h:206
accessControlControlFlag
int accessControlControlFlag
Definition: general_query.cpp:65
InxValPair::inx
int * inx
Definition: objInfo.h:215
COL_QUOTA_LIMIT
#define COL_QUOTA_LIMIT
Definition: rodsGenQuery.h:470
COL_AUDIT_RANGE_START
#define COL_AUDIT_RANGE_START
Definition: rodsGenQuery.h:352
rstrncat
char * rstrncat(char *dest, const char *src, int srcLen, int maxLen)
Definition: stringOpr.cpp:106
LOG_ERROR
#define LOG_ERROR
Definition: rodsLog.h:43
tColumns::defineValue
int defineValue
Definition: general_query.cpp:89
UPPER_CASE_WHERE
#define UPPER_CASE_WHERE
Definition: rodsGenQuery.h:90
SELECT_MIN
#define SELECT_MIN
Definition: rodsGenQuery.h:102
GenQueryInp::selectInp
inxIvalPair_t selectInp
Definition: rodsGenQuery.h:53
GenQueryInp::maxRows
int maxRows
Definition: rodsGenQuery.h:25
orderBySQL
char orderBySQL[16000]
Definition: general_query.cpp:58
GenQueryOut::sqlResult
sqlResult_t sqlResult[50]
Definition: rodsGenQuery.h:72
Tables
struct tTables Tables[500]
chl_gen_query_impl
int chl_gen_query_impl(genQueryInp_t genQueryInp, genQueryOut_t *result)
Definition: general_query.cpp:2293
InxValPair::value
char ** value
Definition: objInfo.h:216
Links
struct tlinks Links[500]
addBetweenClauseToWhere
int addBetweenClauseToWhere(char *inArg)
Definition: general_query.cpp:1404
tableAbbrevs
char tableAbbrevs
Definition: general_query.cpp:98
chl_gen_query_ticket_setup_impl
int chl_gen_query_ticket_setup_impl(const char *ticket, const char *clientAddr)
Definition: general_query.cpp:2278
KeyValPair::value
char ** value
Definition: objInfo.h:123
cmlGetNextRowFromStatement
int cmlGetNextRowFromStatement(int stmtNum, icatSessionStruct *icss)
Definition: mid_level_routines.cpp:459
COL_DATA_NAME
#define COL_DATA_NAME
Definition: rodsGenQuery.h:165
handleMultiCollAVUConditions
void handleMultiCollAVUConditions(int nConditions)
Definition: general_query.cpp:844
nTables
int nTables
Definition: general_query.cpp:86
nColumns
int nColumns
Definition: general_query.cpp:94
addInClauseToWhereForIn
int addInClauseToWhereForIn(char *inArg, int option)
Definition: general_query.cpp:1341
setBlank
int setBlank(char *string, int count)
Definition: general_query.cpp:1144
sessionClientAddr
char sessionClientAddr[(1024+64)]
Definition: general_query.cpp:67
RODS_ZONE_CLIENT_KW
#define RODS_ZONE_CLIENT_KW
Definition: rodsKeyWdDef.h:165
generateSQL
int generateSQL(genQueryInp_t genQueryInp, char *resultingSQL, char *resultingCountSQL)
Definition: general_query.cpp:1824
setTable
int setTable(int column, int sel, int selectOption, int castOption)
Definition: general_query.cpp:640
LOG_DEBUG
#define LOG_DEBUG
Definition: rodsLog.h:23
sColumn
int sColumn(int defineVal, const char *tableName, const char *columnName)
Definition: general_query.cpp:218
GenQueryOut::continueInx
int continueInx
Definition: rodsGenQuery.h:70
CAT_UNKNOWN_TABLE
@ CAT_UNKNOWN_TABLE
Definition: rodsErrorTable.h:438
ANONYMOUS_USER
#define ANONYMOUS_USER
Definition: rodsDef.h:133
GenQueryInp::condInput
keyValPair_t condInput
Definition: rodsGenQuery.h:52
irods::get_virtual_path_separator
std::string get_virtual_path_separator()
Definition: irods_virtual_path.cpp:11
cmlGetFirstRowFromSql
int cmlGetFirstRowFromSql(const char *sql, int *statement, int skipCount, icatSessionStruct *icss)
Definition: mid_level_routines.cpp:382
tTables::tableName
char tableName[64]
Definition: general_query.cpp:79
COL_USER_NAME
#define COL_USER_NAME
Definition: rodsGenQuery.h:132
KeyValPair::keyWord
char ** keyWord
Definition: objInfo.h:122
InxIvalPair::inx
int * inx
Definition: objInfo.h:207
Columns
struct tColumns Columns[500]
GenQueryInp::sqlCondInp
inxValPair_t sqlCondInp
Definition: rodsGenQuery.h:56
cllGetRowCount
int cllGetRowCount(icatSessionStruct *icss, int statementNumber)
Definition: low_level_odbc.cpp:940
MAX_NAME_LEN
#define MAX_NAME_LEN
Definition: rodsDef.h:61
checkCondInputAccess
int checkCondInputAccess(genQueryInp_t genQueryInp, int statementNum, icatSessionStruct *icss, int continueFlag)
Definition: general_query.cpp:2111
whereSQL
char whereSQL[16000]
Definition: general_query.cpp:57
mid_level.hpp
compoundConditionSpecified
int compoundConditionSpecified(char *condition)
Definition: general_query.cpp:922
low_level.hpp
TICKET_KW
#define TICKET_KW
Definition: rodsKeyWdDef.h:109
icatSessionStruct::stmtPtr
icatStmtStrct * stmtPtr[50]
Definition: icatStructs.hpp:30
ADMIN_KW
#define ADMIN_KW
Definition: rodsKeyWdDef.h:62
GenQueryInp::rowOffset
int rowOffset
Definition: rodsGenQuery.h:32
nToFind
int nToFind
Definition: general_query.cpp:96
MAX_LINKS_TABLES_OR_COLUMNS
#define MAX_LINKS_TABLES_OR_COLUMNS
Definition: general_query.cpp:45
GenQueryOut
Definition: rodsGenQuery.h:67
LOCAL_PRIV_USER_AUTH
#define LOCAL_PRIV_USER_AUTH
Definition: rodsUser.h:36
sTableInit
int sTableInit()
Definition: general_query.cpp:179
icatStmtStrct::resultValue
char * resultValue[30]
Definition: icatStructs.hpp:21
tColumns
Definition: general_query.cpp:88
irods.pypyodbc.status
status
Definition: pypyodbc.py:467
GenQueryOut::attriCnt
int attriCnt
Definition: rodsGenQuery.h:69
fkFindName
int fkFindName(const char *tableName)
Definition: general_query.cpp:140
debug
int debug
Definition: general_query.cpp:100
firstCall
int firstCall
Definition: general_query.cpp:51
GenQueryOut::rowCnt
int rowCnt
Definition: rodsGenQuery.h:68
genqAppendAccessCheck
int genqAppendAccessCheck()
Definition: general_query.cpp:1615
cmlGetIntegerValueFromSqlV3
int cmlGetIntegerValueFromSqlV3(const char *sql, rodsLong_t *iVal, icatSessionStruct *icss)
Definition: mid_level_routines.cpp:597
MAX_TSQL
#define MAX_TSQL
Definition: general_query.cpp:47
LOG_NOTICE
#define LOG_NOTICE
Definition: rodsLog.h:33
debug2
int debug2
Definition: general_query.cpp:101
addInClauseToWhereForParentOf
int addInClauseToWhereForParentOf(char *inArg)
Definition: general_query.cpp:1231
InxIvalPair::value
int * value
Definition: objInfo.h:208
tTables
Definition: general_query.cpp:78
InxValPair::len
int len
Definition: objInfo.h:214
icss
icatSessionStruct icss
Definition: db_plugin.cpp:97
cmlCheckDirId
rodsLong_t cmlCheckDirId(const char *dirId, const char *userName, const char *userZone, const char *accessLevel, icatSessionStruct *icss)
Definition: mid_level_routines.cpp:1002
COL_AUDIT_RANGE_END
#define COL_AUDIT_RANGE_END
Definition: rodsGenQuery.h:353
CAT_TOO_MANY_TABLES
@ CAT_TOO_MANY_TABLES
Definition: rodsErrorTable.h:437
CAT_FAILED_TO_LINK_TABLES
@ CAT_FAILED_TO_LINK_TABLES
Definition: rodsErrorTable.h:440
COL_META_RESC_GROUP_ATTR_NAME
#define COL_META_RESC_GROUP_ATTR_NAME
Definition: rodsGenQuery.h:242
SqlResult::value
char * value
Definition: rodsGenQuery.h:64
chlGetLocalZone
int chlGetLocalZone(std::string &)
Definition: icatHighLevelRoutines.cpp:270
insertWhere
int insertWhere(char *condition, int option)
Definition: general_query.cpp:1461
UNINITIALIZED_STATEMENT_NUMBER
const int UNINITIALIZED_STATEMENT_NUMBER
Definition: mid_level.hpp:18
icatStmtStrct::numOfCols
int numOfCols
Definition: icatStructs.hpp:17
RETURN_TOTAL_ROW_COUNT
#define RETURN_TOTAL_ROW_COUNT
Definition: rodsGenQuery.h:86
rodsClient.h
irods_virtual_path.hpp
CAT_NO_ROWS_FOUND
@ CAT_NO_ROWS_FOUND
Definition: rodsErrorTable.h:423
mightNeedGroupBy
int mightNeedGroupBy
Definition: general_query.cpp:60
USER_STRLEN_TOOLONG
@ USER_STRLEN_TOOLONG
Definition: rodsErrorTable.h:237
ORDER_BY_DESC
#define ORDER_BY_DESC
Definition: rodsGenQuery.h:82
COL_COLL_NAME
#define COL_COLL_NAME
Definition: rodsGenQuery.h:189
sTest
int sTest(int i1, int i2)
Definition: general_query.cpp:462
KeyValPair::len
int len
Definition: objInfo.h:121
chlDebugGenQuery
int chlDebugGenQuery(int mode)
Definition: general_query.cpp:2576
COL_META_DATA_ATTR_NAME
#define COL_META_DATA_ATTR_NAME
Definition: rodsGenQuery.h:203
cmlCheckDataObjId
int cmlCheckDataObjId(const char *dataId, const char *userName, const char *zoneName, const char *accessLevel, const char *ticketStr, const char *ticketHost, icatSessionStruct *icss)
Definition: mid_level_routines.cpp:1648
sTable
int sTable(const char *tableName, const char *tableAlias, int cycler)
Definition: general_query.cpp:202
nLinks
int nLinks
Definition: general_query.cpp:76
COL_QUOTA_RESC_ID
#define COL_QUOTA_RESC_ID
Definition: rodsGenQuery.h:469
checkCondition
int checkCondition(char *condition)
Definition: general_query.cpp:1157
generate_iadmin_commands_for_41_to_42_upgrade.host
host
Definition: generate_iadmin_commands_for_41_to_42_upgrade.py:23
MAX_SQL_SIZE_GQ
#define MAX_SQL_SIZE_GQ
Definition: general_query.cpp:49
SqlResult::len
int len
Definition: rodsGenQuery.h:63
QUOTA_QUERY
#define QUOTA_QUERY
Definition: rodsGenQuery.h:88
COL_META_COLL_ATTR_NAME
#define COL_META_COLL_ATTR_NAME
Definition: rodsGenQuery.h:210
icatHighLevelRoutines.hpp
groupBySQL
char groupBySQL[16000]
Definition: general_query.cpp:59
ORDER_BY
#define ORDER_BY
Definition: rodsGenQuery.h:81
LOG_SQL
#define LOG_SQL
Definition: rodsLog.h:9
CAT_INVALID_ARGUMENT
@ CAT_INVALID_ARGUMENT
Definition: rodsErrorTable.h:431
accessControlPriv
int accessControlPriv
Definition: general_query.cpp:64
SELECT_SUM
#define SELECT_SUM
Definition: rodsGenQuery.h:104
MINIMUM_COL_SIZE
#define MINIMUM_COL_SIZE
Definition: general_query.cpp:43
chlGenQuery
int chlGenQuery(genQueryInp_t genQueryInp, genQueryOut_t *result)
Definition: icatHighLevelRoutines.cpp:4462
ZONE_KW
#define ZONE_KW
Definition: rodsKeyWdDef.h:80
NO_DISTINCT
#define NO_DISTINCT
Definition: rodsGenQuery.h:87
COL_QUOTA_USER_ID
#define COL_QUOTA_USER_ID
Definition: rodsGenQuery.h:468
MAX_BIND_VARS
#define MAX_BIND_VARS
Definition: low_level_odbc.hpp:20
cmlFreeStatement
int cmlFreeStatement(int statementNumber, icatSessionStruct *icss)
Definition: mid_level_routines.cpp:374
cllBindVars
const char * cllBindVars[32000]
Definition: low_level_odbc.cpp:48
doUpperCase
int doUpperCase
Definition: general_query.cpp:55
setOrderByUser
void setOrderByUser(genQueryInp_t genQueryInp)
Definition: general_query.cpp:1119
mode
int mode
Definition: filesystem.cpp:104
chlGetRcs
int chlGetRcs(icatSessionStruct **)
Definition: icatHighLevelRoutines.cpp:222
rstrcpy
char * rstrcpy(char *dest, const char *src, int maxLen)
Definition: stringOpr.cpp:51
BAD_FUNCTION_CALL
@ BAD_FUNCTION_CALL
Definition: rodsErrorTable.h:772
NAME_LEN
#define NAME_LEN
Definition: rodsDef.h:55
tTables::tableAlias
char tableAlias[110]
Definition: general_query.cpp:80
COL_QUOTA_OVER
#define COL_QUOTA_OVER
Definition: rodsGenQuery.h:471
icatGeneralQuerySetup
void icatGeneralQuerySetup()
Definition: general_query_setup.cpp:35
COL_META_RESC_ATTR_NAME
#define COL_META_RESC_ATTR_NAME
Definition: rodsGenQuery.h:228
COL_META_USER_ATTR_NAME
#define COL_META_USER_ATTR_NAME
Definition: rodsGenQuery.h:235
tTables::flag
int flag
Definition: general_query.cpp:82
parseUserName
int parseUserName(const char *fullUserNameIn, char *userName, char *userZone)
Definition: rcMisc.cpp:204
type
int type
Definition: filesystem.cpp:103
DISABLE_STRICT_ACL_KW
#define DISABLE_STRICT_ACL_KW
Definition: rodsKeyWdDef.h:285
accessControlZone
char accessControlZone[(1024+64)]
Definition: general_query.cpp:63
icatSessionStruct
Definition: icatStructs.hpp:26
selectSQLInitFlag
int selectSQLInitFlag
Definition: general_query.cpp:54
sGetColumnInfo
int sGetColumnInfo(int defineVal, char **tableName, char **columnName)
Definition: general_query.cpp:235
handleMultiDataAVUConditions
void handleMultiDataAVUConditions(int nConditions)
Definition: general_query.cpp:771
fromCount
int fromCount
Definition: general_query.cpp:61
GenQueryInp::options
int options
Definition: rodsGenQuery.h:34
rodsLong_t
long long rodsLong_t
Definition: rodsType.h:32
selectSQL
char selectSQL[16000]
Definition: general_query.cpp:53