NCBI C++ ToolKit
ncbi_dblb_cli.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbi_dblb_cli.cpp 99891 2023-05-18 18:14:23Z ucko $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Aaron Ucko
27 *
28 * File Description:
29 * Database-centric load-balancer client (useful for scripts)
30 *
31 * ===========================================================================
32 */
33 
34 #include <ncbi_pch.hpp>
35 
36 #include <corelib/ncbiapp.hpp>
37 #include <util/static_map.hpp>
39 #include <connect/ncbi_service.h>
40 #include <connect/ncbi_socket.hpp>
42 
45 #include <dbapi/simple/sdbapi.hpp>
46 
48 
50 {
52 };
53 
55 {
56  static void Delete(SERV_ITER iter) { SERV_Close(iter); }
57 };
58 
59 inline
61 {
62  os << server.GetName() << '\t' << CSocketAPI::ntoa(server.GetHost())
63  << '\t' << server.GetPort();
64  return os;
65 }
66 
67 inline
68 static bool s_IsDBPort(unsigned short port)
69 {
70  // MS SQL consistently uses port 1433, but Sybase is another matter.
71  return (port == 1433 || (port >= 2131 && port <= 2198));
72 }
73 
75 {
76 public:
77  void Init(void);
78  int Run(void);
79 
80 private:
81  void x_InitLookup (CArgDescriptions& arg_desc);
82  void x_InitWhatIs (CArgDescriptions& arg_desc);
83  void x_InitWhereIs(CArgDescriptions& arg_desc);
84  int x_RunLookup (void);
85  int x_RunWhatIs (void);
86  int x_RunWhereIs (void);
87 
89 };
90 
92 {
93  unique_ptr<CCommandArgDescriptions> cmd_desc(new CCommandArgDescriptions);
94  cmd_desc->SetUsageContext(GetArguments().GetProgramBasename(),
95  "Simple database-centric load-balancer client");
96 
97  unique_ptr<CArgDescriptions> arg_desc;
98 
99  arg_desc.reset(new CArgDescriptions);
100  x_InitLookup(*arg_desc);
101  cmd_desc->AddCommand("lookup", arg_desc.release());
102 
103  arg_desc.reset(new CArgDescriptions);
104  x_InitWhatIs(*arg_desc);
105  cmd_desc->AddCommand("whatis", arg_desc.release());
106 
107  arg_desc.reset(new CArgDescriptions);
108  x_InitWhereIs(*arg_desc);
109  cmd_desc->AddCommand("whereis", arg_desc.release());
110 
111  SetupArgDescriptions(cmd_desc.release());
112 }
113 
115 {
116  typedef int (CDBLBClientApp::* TRunner)(void);
117  typedef SStaticPair<const char*, TRunner> TRunnerPair;
118  static const TRunnerPair kRunners[] = {
119  { "lookup", &CDBLBClientApp::x_RunLookup },
120  { "whatis", &CDBLBClientApp::x_RunWhatIs },
121  { "whereis", &CDBLBClientApp::x_RunWhereIs }
122  };
124  DEFINE_STATIC_ARRAY_MAP(TRunnerMap, sc_Runners, kRunners);
125 
126  TRunnerMap::const_iterator it
127  = sc_Runners.find(GetArgs().GetCommand().c_str());
128  _ASSERT(it != sc_Runners.end());
129  return (this->*it->second)();
130 }
131 
133 {
134  arg_desc.SetUsageContext("lookup", "Look up a database server");
135 
136  arg_desc.AddKey
137  ("service", "Service",
138  "Desired service name; use -url to supply a full DBAPI URL.",
140  arg_desc.AddKey("url", "URL",
141  "DBAPI URL consolidating all of the above",
143  arg_desc.SetConstraint("url", new CArgAllow_Regexp("dbapi://.*"));
144  arg_desc.SetDependency("url", CArgDescriptions::eExcludes, "service");
145 
146  arg_desc.AddDefaultKey("username", "Name",
147  "Username for confirming usability",
148  CArgDescriptions::eString, "anyone");
149  arg_desc.SetDependency("username", CArgDescriptions::eRequires, "service");
150  arg_desc.AddDefaultKey("password", "Password",
151  "Password corresponding to username",
152  CArgDescriptions::eString, "allowed");
153  arg_desc.SetDependency("password", CArgDescriptions::eRequires, "service");
154  arg_desc.AddOptionalKey("database", "Name", "Database name to try using",
156  arg_desc.SetDependency("database", CArgDescriptions::eRequires, "service");
157  arg_desc.AddFlag("kerberos",
158  "Authenticate via existing Kerberos credentials");
159  arg_desc.SetDependency("kerberos", CArgDescriptions::eExcludes,
160  "username");
161  arg_desc.SetDependency("kerberos", CArgDescriptions::eExcludes,
162  "password");
163 #if 0 // not yet implemented
164  arg_desc.AddDefaultKey("limit", "N", "Maximum number of servers to return",
166  arg_desc.SetConstraint("limit", new CArgAllow_Integers(1, kMax_Int));
167 #endif
168 }
169 
171 {
172  const CArgs& args = GetArgs();
173  bool use_kerberos = args["kerberos"].HasValue();
174  if (use_kerberos) {
175  TDbapi_CanUseKerberos::SetDefault(true);
176  }
177 
178  CSDB_ConnectionParam param;
179  if (args["url"].HasValue()) {
180  param.Set(args["url"].AsString());
181  } else {
182  param.Set(args["service"].AsString());
183  if ( !use_kerberos && args["username"].HasValue()) {
185  args["username"].AsString());
186  }
187  if ( !use_kerberos && args["password"].HasValue()) {
189  args["password"].AsString());
190  }
191  if (args["database"].HasValue()) {
193  args["database"].AsString());
194  }
195  }
196 
197  CDatabase db(param);
198  CQuery query;
199  {{
202  db.Connect();
203  query = db.NewQuery();
205  }}
206  // Hack to obtain the actual server name
207  try {
208  query.Execute();
209  } catch (CSDB_Exception& e) {
210  const string& name = e.GetServerName();
211  TSvrRef server,
212  pref(new CDBServer(name, CSocketAPI::gethostbyname(name)));
214  if (mapper != NULL) {
215  // server.Reset(mapper->GetServer(e.GetServerName()));
216  const string& service = param.Get(CSDB_ConnectionParam::eService);
217  mapper->SetPreference(service, pref);
218  server.Reset(mapper->GetServer(service));
219  }
220  if (server.Empty() || server->GetName().empty()) {
221  server.Reset(pref);
222  }
223  cout << *server << '\n';
224  }
225 
226  return 0;
227 }
228 
230 {
231  arg_desc.SetUsageContext("whatis", "Identify a name");
232  arg_desc.AddPositional("name", "Name to identify",
234 }
235 
237 {
238  const CArgs& args = GetArgs();
239  const string& name = args["name"].AsString();
240 
242  (ConnNetInfo_Create(name.c_str()));
244  (SERV_Open(name.c_str(), fSERV_Any, SERV_ANYHOST, net_info.get()));
245  TSERV_Type types_seen = 0;
246  for (;;) {
247  SSERV_InfoCPtr serv_info = SERV_GetNextInfo(iter.get());
248  if (serv_info == NULL) {
249  break;
250  } else if ((types_seen & serv_info->type) != 0) {
251  continue;
252  } else {
253  types_seen |= serv_info->type;
254  }
255 
256  if (serv_info->type == fSERV_Standalone) {
258  _ASSERT(mapper != NULL);
259  TSvrRef ref = mapper->GetServer(name);
260  if (ref.NotEmpty() && ref->GetHost() != 0
261  && !ref->GetName().empty()
262  /* && s_IsDBPort(ref->GetPort()) */ ) {
263  NcbiCout << name << " is a database service.\n";
264  continue;
265  }
266  }
267  NcbiCout << name << " is a service (type "
268  << SERV_TypeStr(serv_info->type) << ").\n";
269  }
270 
271  iter.reset(SERV_Open(name.c_str(), fSERV_Dns, SERV_ANYHOST,
272  net_info.get()));
273  SSERV_InfoCPtr serv_info = SERV_GetNextInfo(iter.get());
274  if (serv_info != NULL) {
275  types_seen |= serv_info->type;
276  if (s_IsDBPort(serv_info->port)) {
277  string hostname = CSocketAPI::gethostbyaddr(serv_info->host);
278  if (hostname.empty()) {
279  hostname = CSocketAPI::ntoa(serv_info->host);
280  }
281  NcbiCout << name << " is a registered database server alias on "
282  << hostname << ".\n";
283  } else {
284  NcbiCout << name << " is a \"DNS\" service record.\n";
285  }
286  }
287 
288  unsigned int ip = CSocketAPI::gethostbyname(name);
289  if (ip != 0) {
290  NcbiCout << name << " is a host (" << CSocketAPI::ntoa(ip) << ").\n";
291  } else if (types_seen == 0) {
292  NcbiCout << name << " is unknown to LBSM or DNS.\n";
293  return 1;
294  }
295 
296  return 0;
297 }
298 
300 {
301  arg_desc.SetUsageContext("whereis",
302  "List all instances of a load-balanced service");
303 
304  arg_desc.AddDefaultKey
305  ("type", "Type", "Service type (case-insensitive)",
306  CArgDescriptions::eString, "DBLB");
307  unique_ptr<CArgAllow_Strings> type_strings
308  (&(*new CArgAllow_Strings(NStr::eNocase), "ANY", "DBLB", "HTTP"));
309  for (TSERV_Type t = 1; t <= fSERV_All; t <<= 1) {
310  const char* name = SERV_TypeStr(static_cast<ESERV_Type>(t));
311  if (name == NULL || name[0] == '\0') {
312  break;
313  } else {
314  type_strings->Allow(name);
315  }
316  }
317  arg_desc.SetConstraint("type", type_strings.release());
318 
319  arg_desc.AddFlag("stateless", "Stateless servers only" );
320  arg_desc.AddFlag("reverse-dns", "LB-DNS translation" );
321  arg_desc.AddFlag("include-down", "Include instances that are down");
322  arg_desc.AddFlag("include-standby", "Include instances on standby" );
323  arg_desc.AddFlag("include-reserved", "Include reserved instances" );
324  arg_desc.AddFlag("include-suppressed", "Include suppressed instances" );
325  arg_desc.AddFlag("include-inactive", "Include inactive instances" );
326  arg_desc.AddFlag("include-private", "Include private instances" );
327  arg_desc.AddFlag("promiscuous", "Include all of the above" );
328 
329  arg_desc.AddPositional("service", "Service name",
331 }
332 
334 {
335  const CArgs& args = GetArgs();
336  const string& service = args["service"].AsString();
337  const string& type_str = args["type" ].AsString();
339  int status = 1;
340 
341  if (NStr::EqualNocase(type_str, "dblb")) {
343  _ASSERT(mapper != NULL);
344  for (;;) {
345  TSvrRef ref = mapper->GetServer(service);
346  if (ref.Empty() || ref->GetHost() == 0
347  || ref->GetName().empty()) {
348  break;
349  }
350  status = 0;
351  NcbiCout << *ref << "\t# type=DBLB\n";
352  mapper->Exclude(service, ref);
353  }
354  return status;
355  } else if (SERV_ReadType(type_str.c_str(),
356  reinterpret_cast<ESERV_Type*>(&type)) == NULL) {
357  _ASSERT(NStr::EqualNocase(type_str, "any"));
358  }
359 
360  if (args["stateless"]) { type |= fSERV_Stateless; }
361  if (args["reverse-dns"]) { type |= fSERV_ReverseDns; }
362  if (args["include-down"]) { type |= fSERV_IncludeDown; }
363  if (args["include-standby"]) { type |= fSERV_IncludeStandby; }
364  if (args["include-reserved"]) { type |= fSERV_IncludeReserved; }
365  if (args["include-suppressed"]) { type |= fSERV_IncludeSuppressed; }
366  if (args["include-inactive"]) { type |= fSERV_IncludeInactive; }
367  if (args["include-private"]) { type |= fSERV_IncludePrivate; }
368  if (args["promiscuous"]) { type |= fSERV_Promiscuous; }
369 
371  (ConnNetInfo_Create(service.c_str()));
372  // Unavailable instances aren't showing up even with fSERV_Promiscuous,
373  // but aren't strictly necessary to mention anyway.
375  (SERV_Open(service.c_str(), type, SERV_ANYHOST, net_info.get()));
376  for (;;) {
377  SSERV_InfoCPtr serv_info = SERV_GetNextInfo(iter.get());
378  if (serv_info == NULL) {
379  break;
380  }
381  status = 0;
382  CDBServer server(CSocketAPI::gethostbyaddr(serv_info->host),
383  serv_info->host, serv_info->port);
384  if (serv_info->rate <= 0.0) {
385  NcbiCout << "# ";
386  }
387  NcbiCout << server << "\t# type=" << SERV_TypeStr(serv_info->type)
388  << '\n';
389  }
390  return status;
391 }
392 
394 {
395 #if 0 // CRuntimeData and GetRuntimeData are protected
396  return &(dynamic_cast<CDBConnectionFactory&>
398  .GetRuntimeData(kEmptyStr).GetDBServiceMapper());
399 #else
400  static CDBLB_ServiceMapper mapper(&GetConfig());
401  return &mapper;
402 #endif
403 }
404 
406 
408 
409 int main(int argc, const char** argv)
410 {
411  return CDBLBClientApp().AppMain(argc, argv);
412 }
AutoPtr –.
Definition: ncbimisc.hpp:401
CArgAllow_Integers –.
Definition: ncbiargs.hpp:1751
CArgAllow_Regexp –.
Definition: arg_regexp.hpp:61
CArgAllow_Strings –.
Definition: ncbiargs.hpp:1641
CArgDescriptions –.
Definition: ncbiargs.hpp:541
CArgs –.
Definition: ncbiargs.hpp:379
CCommandArgDescriptions –.
Definition: ncbiargs.hpp:1381
int x_RunWhereIs(void)
int Run(void)
Run the application.
void Init(void)
Initialize the application.
int x_RunLookup(void)
IDBServiceMapper * x_GetServiceMapper(void)
int x_RunWhatIs(void)
void x_InitLookup(CArgDescriptions &arg_desc)
void x_InitWhereIs(CArgDescriptions &arg_desc)
void x_InitWhatIs(CArgDescriptions &arg_desc)
CDBLBServerNamePolicy.
IDBServiceMapper.
Uint2 GetPort(void) const
const string & GetName(void) const
Uint4 GetHost(void) const
Database connection object.
Definition: sdbapi.hpp:1137
void Connect(void)
Explicitly (re)connect to the database server.
Definition: sdbapi.cpp:2013
CQuery NewQuery(void)
Get new CQuery object for this database.
Definition: sdbapi.cpp:2082
CRef< IDBConnectionFactory > GetConnectionFactory(void) const
Retrieve a connection factory.
static CDbapiConnMgr & Instance(void)
Get access to the class instance.
Guard for collecting diag messages (affects the current thread only).
Definition: ncbidiag.hpp:1300
Object used to execute queries and stored procedures on the database server and retrieve result sets.
Definition: sdbapi.hpp:232
Convenience class to initialize database connection parameters from URL-like strings and/or applicati...
Definition: sdbapi.hpp:933
CSDB_ConnectionParam & Set(EParam param, const string &value, TSetFlags flags=0)
Set one of the "essential" database connection parameters, unless overridden in a configuration file.
Definition: sdbapi.hpp:1600
@ eService
Named service, interfaces-file alias, or raw server name, per http://ncbi.github.io/cxx-toolkit/pages...
Definition: sdbapi.hpp:1016
string Get(EParam param, EWithOverrides with_overrides=eWithoutOverrides) const
Get one of the "essential" database connection parameters.
Definition: sdbapi.hpp:1542
Exception class used throughout the API.
Definition: sdbapi.hpp:68
const string & GetServerName(void) const
Definition: sdbapi.hpp:1412
class CStaticArrayMap<> provides access to a static array in much the same way as CStaticArraySet<>,...
Definition: static_map.hpp:175
IDBServiceMapper.
virtual TSvrRef GetServer(const string &service)=0
Map a service to a server.
virtual void SetPreference(const string &service, const TSvrRef &preferred_server, double preference=100)=0
Set up mapping preferences for a service preference - value between 0 and 100 (0 means *no particular...
virtual void Exclude(const string &service, const TSvrRef &server)
Exclude a server from the mapping for a service.
static const char ip[]
Definition: des.c:75
void reset(element_type *p=0, EOwnership ownership=eTakeOwnership)
Reset will delete the old pointer (if owned), set content to the new value, and assume the ownership ...
Definition: ncbimisc.hpp:480
const CNcbiRegistry & GetConfig(void) const
Get the application's cached configuration parameters (read-only).
virtual const CArgs & GetArgs(void) const
Get parsed command line arguments.
Definition: ncbiapp.cpp:285
int AppMain(int argc, const char *const *argv, const char *const *envp=0, EAppDiagStream diag=eDS_Default, const char *conf=NcbiEmptyCStr, const string &name=NcbiEmptyString)
Main function (entry point) for the NCBI application.
Definition: ncbiapp.cpp:799
virtual void SetupArgDescriptions(CArgDescriptions *arg_desc)
Setup the command line argument descriptions.
Definition: ncbiapp.cpp:1175
element_type * get(void) const
Get pointer.
Definition: ncbimisc.hpp:469
const CNcbiArguments & GetArguments(void) const
Get the application's cached unprocessed command-line arguments.
void AddFlag(const string &name, const string &comment, CBoolEnum< EFlagValue > set_value=eFlagHasValueIfSet, TFlags flags=0)
Add description for flag argument.
Definition: ncbiargs.cpp:2459
void SetConstraint(const string &name, const CArgAllow *constraint, EConstraintNegate negate=eConstraint)
Set additional user defined constraint on argument value.
Definition: ncbiargs.cpp:2591
void SetDependency(const string &arg1, EDependency dep, const string &arg2)
Define a dependency.
Definition: ncbiargs.cpp:2618
void AddKey(const string &name, const string &synopsis, const string &comment, EType type, TFlags flags=0)
Add description for mandatory key.
Definition: ncbiargs.cpp:2412
void SetUsageContext(const string &usage_name, const string &usage_description, bool usage_sort_args=false, SIZE_TYPE usage_width=78)
Set extra info to be used by PrintUsage().
Definition: ncbiargs.cpp:3299
void AddPositional(const string &name, const string &comment, EType type, TFlags flags=0)
Add description for mandatory positional argument.
Definition: ncbiargs.cpp:2471
void AddOptionalKey(const string &name, const string &synopsis, const string &comment, EType type, TFlags flags=0)
Add description for optional key without default value.
Definition: ncbiargs.cpp:2427
void AddDefaultKey(const string &name, const string &synopsis, const string &comment, EType type, const string &default_value, TFlags flags=0, const string &env_var=kEmptyStr, const char *display_value=nullptr)
Add description for optional key with default value.
Definition: ncbiargs.cpp:2442
@ eRequires
One argument requires another.
Definition: ncbiargs.hpp:956
@ eExcludes
One argument excludes another.
Definition: ncbiargs.hpp:957
@ eString
An arbitrary string.
Definition: ncbiargs.hpp:589
@ eInteger
Convertible into an integer number (int or Int8)
Definition: ncbiargs.hpp:592
#define NULL
Definition: ncbistd.hpp:225
void SetAction(EAction action)
Specify on-destroy action.
Definition: ncbidiag.hpp:1362
@ ePrint
Print all collected messages as is.
Definition: ncbidiag.hpp:1304
@ eDiscard
Discard collected messages, default.
Definition: ncbidiag.hpp:1305
@ eDiag_Info
Informational message.
Definition: ncbidiag.hpp:651
@ eDiag_Fatal
Fatal error – guarantees exit(or abort)
Definition: ncbidiag.hpp:655
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:773
bool NotEmpty(void) const THROWS_NONE
Check if CRef is not empty – pointing to an object and has a non-null value.
Definition: ncbiobj.hpp:726
bool Empty(void) const THROWS_NONE
Check if CRef is empty – not pointing to any object, which means having a null value.
Definition: ncbiobj.hpp:719
#define kMax_Int
Definition: ncbi_limits.h:184
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
ESERV_Type
SSERV_InfoCPtr SERV_GetNextInfo(SERV_ITER iter)
Same as "SERV_GetNextInfoEx(., 0)" – i.e.
Definition: ncbi_service.c:936
void SERV_Close(SERV_ITER iter)
Deallocate the iterator.
Definition: ncbi_service.c:993
#define SERV_ANYHOST
Definition: ncbi_service.h:55
const char * SERV_ReadType(const char *str, ESERV_Type *type)
const char * SERV_TypeStr(ESERV_Type type)
SERV_ITER SERV_Open(const char *service, TSERV_Type types, unsigned int preferred_host, const SConnNetInfo *net_info)
Same as "SERV_OpenEx(., ., ., ., 0, 0)" – i.e.
Definition: ncbi_service.c:809
unsigned int TSERV_Type
Bitwise OR of ESERV_Type[Special].
Definition: ncbi_service.h:94
unsigned int host
unsigned short port
ESERV_Type type
@ fSERV_Standalone
@ fSERV_Dns
@ fSERV_ReverseDns
LB-DNS translation.
Definition: ncbi_service.h:84
@ fSERV_IncludeSuppressed
Definition: ncbi_service.h:89
@ fSERV_IncludeInactive
Definition: ncbi_service.h:90
@ fSERV_All
Server type mask.
Definition: ncbi_service.h:80
@ fSERV_Stateless
Stateless servers only.
Definition: ncbi_service.h:81
@ fSERV_IncludeStandby
Definition: ncbi_service.h:87
@ fSERV_IncludeDown
Definition: ncbi_service.h:86
@ fSERV_Any
Definition: ncbi_service.h:79
@ fSERV_Promiscuous
Evrthng and the kitchen sink.
Definition: ncbi_service.h:92
@ fSERV_IncludeReserved
Definition: ncbi_service.h:88
@ fSERV_IncludePrivate
Definition: ncbi_service.h:91
static string ntoa(unsigned int host)
BSD-like API. NB: when int, "host" must be in network byte order.
static unsigned int gethostbyname(const string &host, ESwitch log=eOff)
Return 0 on error.
static string gethostbyaddr(unsigned int host, ESwitch log=eOff)
Return empty string on error.
IO_PREFIX::ostream CNcbiOstream
Portable alias for ostream.
Definition: ncbistre.hpp:149
#define NcbiCout
Definition: ncbistre.hpp:543
#define kEmptyStr
Definition: ncbistr.hpp:123
static bool EqualNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive equality of a substring with another string.
Definition: ncbistr.hpp:5352
@ eNocase
Case insensitive compare.
Definition: ncbistr.hpp:1206
SConnNetInfo * ConnNetInfo_Create(const char *service)
void ConnNetInfo_Destroy(SConnNetInfo *net_info)
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
static MDB_envinfo info
Definition: mdb_load.c:37
int main(int argc, const char **argv)
CNcbiOstream & operator<<(CNcbiOstream &os, CDBServer &server)
static bool s_IsDBPort(unsigned short port)
USING_NCBI_SCOPE
EIPRangeType t
Definition: ncbi_localip.c:101
Defines the CNcbiApplication and CAppException classes for creating NCBI applications.
#define DEFINE_STATIC_ARRAY_MAP(Type, Var, Array)
Definition: static_set.hpp:888
static void Delete(SConnNetInfo *info)
static void Delete(SERV_ITER iter)
Template structure SStaticPair is simlified replacement of STL pair<> Main reason of introducing this...
Definition: static_set.hpp:60
static string query
Definition: type.c:6
#define _ASSERT
CArgAllow_Regexp – regexp based constraint for argument value.
Modified on Sat Dec 09 04:44:23 2023 by modify_doxy.py rev. 669887