DYT/Tool/OpenSceneGraph-3.6.5/include/ogr_swq.h
2024-12-25 07:49:36 +08:00

530 lines
15 KiB
C++

/******************************************************************************
*
* Component: OGDI Driver Support Library
* Purpose: Generic SQL WHERE Expression Evaluator Declarations.
* Author: Frank Warmerdam <warmerdam@pobox.com>
*
******************************************************************************
* Copyright (C) 2001 Information Interoperability Institute (3i)
* Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies, that
* both the copyright notice and this permission notice appear in
* supporting documentation, and that the name of 3i not be used
* in advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. 3i makes no
* representations about the suitability of this software for any purpose.
* It is provided "as is" without express or implied warranty.
****************************************************************************/
#ifndef SWQ_H_INCLUDED_
#define SWQ_H_INCLUDED_
#ifndef DOXYGEN_SKIP
#include "cpl_conv.h"
#include "cpl_string.h"
#include "ogr_core.h"
#include <list>
#include <map>
#include <vector>
#include <set>
#if defined(_WIN32) && !defined(strcasecmp)
#define strcasecmp stricmp
#endif
// Used for swq_summary.oSetDistinctValues and oVectorDistinctValues
#define SZ_OGR_NULL "__OGR_NULL__"
typedef enum
{
SWQ_OR,
SWQ_AND,
SWQ_NOT,
SWQ_EQ,
SWQ_NE,
SWQ_GE,
SWQ_LE,
SWQ_LT,
SWQ_GT,
SWQ_LIKE,
SWQ_ILIKE,
SWQ_ISNULL,
SWQ_IN,
SWQ_BETWEEN,
SWQ_ADD,
SWQ_SUBTRACT,
SWQ_MULTIPLY,
SWQ_DIVIDE,
SWQ_MODULUS,
SWQ_CONCAT,
SWQ_SUBSTR,
SWQ_HSTORE_GET_VALUE,
SWQ_AVG,
SWQ_AGGREGATE_BEGIN = SWQ_AVG,
SWQ_MIN,
SWQ_MAX,
SWQ_COUNT,
SWQ_SUM,
SWQ_STDDEV_POP,
SWQ_STDDEV_SAMP,
SWQ_AGGREGATE_END = SWQ_STDDEV_SAMP,
SWQ_CAST,
SWQ_CUSTOM_FUNC, /* only if parsing done in bAcceptCustomFuncs mode */
SWQ_ARGUMENT_LIST /* temporary value only set during parsing and replaced by
something else at the end */
} swq_op;
typedef enum
{
SWQ_INTEGER,
SWQ_INTEGER64,
SWQ_FLOAT,
SWQ_STRING,
SWQ_BOOLEAN, // integer
SWQ_DATE, // string
SWQ_TIME, // string
SWQ_TIMESTAMP, // string
SWQ_GEOMETRY,
SWQ_NULL,
SWQ_OTHER,
SWQ_ERROR
} swq_field_type;
#define SWQ_IS_INTEGER(x) ((x) == SWQ_INTEGER || (x) == SWQ_INTEGER64)
typedef enum
{
SNT_CONSTANT,
SNT_COLUMN,
SNT_OPERATION
} swq_node_type;
class swq_field_list;
class swq_expr_node;
class swq_select;
class OGRGeometry;
struct CPL_UNSTABLE_API swq_evaluation_context
{
bool bUTF8Strings = false;
};
typedef swq_expr_node *(*swq_field_fetcher)(swq_expr_node *op,
void *record_handle);
typedef swq_expr_node *(*swq_op_evaluator)(
swq_expr_node *op, swq_expr_node **sub_field_values,
const swq_evaluation_context &sContext);
typedef swq_field_type (*swq_op_checker)(
swq_expr_node *op, int bAllowMismatchTypeOnFieldComparison);
class swq_custom_func_registrar;
class CPL_UNSTABLE_API swq_expr_node
{
swq_expr_node *Evaluate(swq_field_fetcher pfnFetcher, void *record,
const swq_evaluation_context &sContext,
int nRecLevel);
void reset();
public:
swq_expr_node();
swq_expr_node(const swq_expr_node &);
swq_expr_node(swq_expr_node &&);
swq_expr_node &operator=(const swq_expr_node &);
swq_expr_node &operator=(swq_expr_node &&);
bool operator==(const swq_expr_node &) const;
explicit swq_expr_node(const char *);
explicit swq_expr_node(int);
explicit swq_expr_node(GIntBig);
explicit swq_expr_node(double);
explicit swq_expr_node(OGRGeometry *);
explicit swq_expr_node(swq_op);
~swq_expr_node();
void MarkAsTimestamp();
CPLString UnparseOperationFromUnparsedSubExpr(char **apszSubExpr);
char *Unparse(swq_field_list *, char chColumnQuote);
void Dump(FILE *fp, int depth);
swq_field_type Check(swq_field_list *, int bAllowFieldsInSecondaryTables,
int bAllowMismatchTypeOnFieldComparison,
swq_custom_func_registrar *poCustomFuncRegistrar,
int depth = 0);
swq_expr_node *Evaluate(swq_field_fetcher pfnFetcher, void *record,
const swq_evaluation_context &sContext);
swq_expr_node *Clone();
void ReplaceBetweenByGEAndLERecurse();
void PushNotOperationDownToStack();
swq_node_type eNodeType = SNT_CONSTANT;
swq_field_type field_type = SWQ_INTEGER;
/* only for SNT_OPERATION */
void PushSubExpression(swq_expr_node *);
void ReverseSubExpressions();
swq_op nOperation = SWQ_OR;
int nSubExprCount = 0;
swq_expr_node **papoSubExpr = nullptr;
/* only for SNT_COLUMN */
int field_index = 0;
int table_index = 0;
char *table_name = nullptr;
/* only for SNT_CONSTANT */
int is_null = false;
GIntBig int_value = 0;
double float_value = 0.0;
OGRGeometry *geometry_value = nullptr;
/* shared by SNT_COLUMN, SNT_CONSTANT and also possibly SNT_OPERATION when
*/
/* nOperation == SWQ_CUSTOM_FUNC */
char *string_value = nullptr; /* column name when SNT_COLUMN */
// May be transiently used by swq_parser.h, but should not be relied upon
// after parsing. swq_col_def.bHidden captures it afterwards.
bool bHidden = false;
static CPLString QuoteIfNecessary(const CPLString &, char chQuote = '\'');
static CPLString Quote(const CPLString &, char chQuote = '\'');
};
typedef struct
{
const char *pszName;
swq_op eOperation;
swq_op_evaluator pfnEvaluator;
swq_op_checker pfnChecker;
} swq_operation;
class CPL_UNSTABLE_API swq_op_registrar
{
public:
static const swq_operation *GetOperator(const char *);
static const swq_operation *GetOperator(swq_op eOperation);
};
class CPL_UNSTABLE_API swq_custom_func_registrar
{
public:
virtual ~swq_custom_func_registrar()
{
}
virtual const swq_operation *GetOperator(const char *) = 0;
};
typedef struct
{
char *data_source;
char *table_name;
char *table_alias;
} swq_table_def;
class CPL_UNSTABLE_API swq_field_list
{
public:
int count;
char **names;
swq_field_type *types;
int *table_ids;
int *ids;
int table_count;
swq_table_def *table_defs;
};
class CPL_UNSTABLE_API swq_parse_context
{
public:
swq_parse_context()
: nStartToken(0), pszInput(nullptr), pszNext(nullptr),
pszLastValid(nullptr), bAcceptCustomFuncs(FALSE), poRoot(nullptr),
poCurSelect(nullptr)
{
}
int nStartToken;
const char *pszInput;
const char *pszNext;
const char *pszLastValid;
int bAcceptCustomFuncs;
swq_expr_node *poRoot;
swq_select *poCurSelect;
};
/* Compile an SQL WHERE clause into an internal form. The field_list is
** the list of fields in the target 'table', used to render where into
** field numbers instead of names.
*/
int CPL_UNSTABLE_API swqparse(swq_parse_context *context);
int CPL_UNSTABLE_API swqlex(swq_expr_node **ppNode, swq_parse_context *context);
void CPL_UNSTABLE_API swqerror(swq_parse_context *context, const char *msg);
int CPL_UNSTABLE_API swq_identify_field(const char *table_name,
const char *token,
swq_field_list *field_list,
swq_field_type *this_type,
int *table_id);
CPLErr CPL_UNSTABLE_API
swq_expr_compile(const char *where_clause, int field_count, char **field_list,
swq_field_type *field_types, int bCheck,
swq_custom_func_registrar *poCustomFuncRegistrar,
swq_expr_node **expr_root);
CPLErr CPL_UNSTABLE_API
swq_expr_compile2(const char *where_clause, swq_field_list *field_list,
int bCheck, swq_custom_func_registrar *poCustomFuncRegistrar,
swq_expr_node **expr_root);
/*
** Evaluation related.
*/
int CPL_UNSTABLE_API swq_test_like(const char *input, const char *pattern);
swq_expr_node CPL_UNSTABLE_API *
SWQGeneralEvaluator(swq_expr_node *, swq_expr_node **,
const swq_evaluation_context &sContext);
swq_field_type CPL_UNSTABLE_API
SWQGeneralChecker(swq_expr_node *node, int bAllowMismatchTypeOnFieldComparison);
swq_expr_node CPL_UNSTABLE_API *
SWQCastEvaluator(swq_expr_node *, swq_expr_node **,
const swq_evaluation_context &sContext);
swq_field_type CPL_UNSTABLE_API
SWQCastChecker(swq_expr_node *node, int bAllowMismatchTypeOnFieldComparison);
const char CPL_UNSTABLE_API *SWQFieldTypeToString(swq_field_type field_type);
/****************************************************************************/
#define SWQP_ALLOW_UNDEFINED_COL_FUNCS 0x01
#define SWQM_SUMMARY_RECORD 1
#define SWQM_RECORDSET 2
#define SWQM_DISTINCT_LIST 3
typedef enum
{
SWQCF_NONE = 0,
SWQCF_AVG = SWQ_AVG,
SWQCF_MIN = SWQ_MIN,
SWQCF_MAX = SWQ_MAX,
SWQCF_COUNT = SWQ_COUNT,
SWQCF_SUM = SWQ_SUM,
SWQCF_STDDEV_POP = SWQ_STDDEV_POP,
SWQCF_STDDEV_SAMP = SWQ_STDDEV_SAMP,
SWQCF_CUSTOM
} swq_col_func;
typedef struct
{
swq_col_func col_func;
char *table_name;
char *field_name;
char *field_alias;
int table_index;
int field_index;
swq_field_type field_type;
swq_field_type target_type;
OGRFieldSubType target_subtype;
int field_length;
int field_precision;
int distinct_flag;
bool bHidden;
OGRwkbGeometryType eGeomType;
int nSRID;
swq_expr_node *expr;
} swq_col_def;
class CPL_UNSTABLE_API swq_summary
{
public:
struct Comparator
{
bool bSortAsc;
swq_field_type eType;
Comparator() : bSortAsc(true), eType(SWQ_STRING)
{
}
bool operator()(const CPLString &, const CPLString &) const;
};
//! Return the sum, using Kahan-Babuska-Neumaier algorithm.
// Cf cf KahanBabushkaNeumaierSum of https://en.wikipedia.org/wiki/Kahan_summation_algorithm#Further_enhancements
double sum() const
{
return sum_only_finite_terms ? sum_acc + sum_correction : sum_acc;
}
GIntBig count = 0;
std::vector<CPLString> oVectorDistinctValues{};
std::set<CPLString, Comparator> oSetDistinctValues{};
bool sum_only_finite_terms = true;
// Sum accumulator. To get the accurate sum, use the sum() method
double sum_acc = 0.0;
// Sum correction term.
double sum_correction = 0.0;
double min = 0.0;
double max = 0.0;
// Welford's online algorithm for variance:
// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm
double mean_for_variance = 0.0;
double sq_dist_from_mean_acc = 0.0; // "M2"
CPLString osMin{};
CPLString osMax{};
};
typedef struct
{
char *table_name;
char *field_name;
int table_index;
int field_index;
int ascending_flag;
} swq_order_def;
typedef struct
{
int secondary_table;
swq_expr_node *poExpr;
} swq_join_def;
class CPL_UNSTABLE_API swq_select_parse_options
{
public:
swq_custom_func_registrar *poCustomFuncRegistrar;
int bAllowFieldsInSecondaryTablesInWhere;
int bAddSecondaryTablesGeometryFields;
int bAlwaysPrefixWithTableName;
int bAllowDistinctOnGeometryField;
int bAllowDistinctOnMultipleFields;
swq_select_parse_options()
: poCustomFuncRegistrar(nullptr),
bAllowFieldsInSecondaryTablesInWhere(FALSE),
bAddSecondaryTablesGeometryFields(FALSE),
bAlwaysPrefixWithTableName(FALSE),
bAllowDistinctOnGeometryField(FALSE),
bAllowDistinctOnMultipleFields(FALSE)
{
}
};
class CPL_UNSTABLE_API swq_select
{
void postpreparse();
CPL_DISALLOW_COPY_ASSIGN(swq_select)
public:
swq_select();
~swq_select();
int query_mode = 0;
char *raw_select = nullptr;
int PushField(swq_expr_node *poExpr, const char *pszAlias,
bool distinct_flag, bool bHidden);
int PushExcludeField(swq_expr_node *poExpr);
int result_columns() const
{
return static_cast<int>(column_defs.size());
}
std::vector<swq_col_def> column_defs{};
std::vector<swq_summary> column_summary{};
int PushTableDef(const char *pszDataSource, const char *pszTableName,
const char *pszAlias);
int table_count = 0;
swq_table_def *table_defs = nullptr;
void PushJoin(int iSecondaryTable, swq_expr_node *poExpr);
int join_count = 0;
swq_join_def *join_defs = nullptr;
swq_expr_node *where_expr = nullptr;
void PushOrderBy(const char *pszTableName, const char *pszFieldName,
int bAscending);
int order_specs = 0;
swq_order_def *order_defs = nullptr;
void SetLimit(GIntBig nLimit);
GIntBig limit = -1;
void SetOffset(GIntBig nOffset);
GIntBig offset = 0;
swq_select *poOtherSelect = nullptr;
void PushUnionAll(swq_select *poOtherSelectIn);
CPLErr preparse(const char *select_statement,
int bAcceptCustomFuncs = FALSE);
CPLErr expand_wildcard(swq_field_list *field_list,
int bAlwaysPrefixWithTableName);
CPLErr parse(swq_field_list *field_list,
swq_select_parse_options *poParseOptions);
char *Unparse();
bool bExcludedGeometry = false;
private:
bool IsFieldExcluded(int src_index, const char *table, const char *field);
// map of EXCLUDE columns keyed according to the index of the
// asterisk with which it should be associated. key of -1 is
// used for column lists that have not yet been associated with
// an asterisk.
std::map<int, std::list<swq_col_def>> m_exclude_fields{};
};
/* This method should generally be invoked with pszValue set, except when
* called on a non-DISTINCT column definition of numeric type (SWQ_BOOLEAN,
* SWQ_INTEGER, SWQ_INTEGER64, SWQ_FLOAT), in which case pdfValue should
* rather be set.
*/
const char CPL_UNSTABLE_API *swq_select_summarize(swq_select *select_info,
int dest_column,
const char *pszValue,
const double *pdfValue);
int CPL_UNSTABLE_API swq_is_reserved_keyword(const char *pszStr);
char CPL_UNSTABLE_API *OGRHStoreGetValue(const char *pszHStore,
const char *pszSearchedKey);
#ifdef GDAL_COMPILATION
void swq_fixup(swq_parse_context *psParseContext);
swq_expr_node *swq_create_and_or_or(swq_op op, swq_expr_node *left,
swq_expr_node *right);
int swq_test_like(const char *input, const char *pattern, char chEscape,
bool insensitive, bool bUTF8Strings);
#endif
#endif /* #ifndef DOXYGEN_SKIP */
#endif /* def SWQ_H_INCLUDED_ */