CPLErr swq_select::parse( swq_field_list *field_list, swq_select_parse_options* poParseOptions ) { int i; CPLErr eError; int bAlwaysPrefixWithTableName = poParseOptions && poParseOptions->bAlwaysPrefixWithTableName; eError = expand_wildcard( field_list, bAlwaysPrefixWithTableName ); if( eError != CE_None ) return eError; swq_custom_func_registrar* poCustomFuncRegistrar = NULL; if( poParseOptions != NULL ) poCustomFuncRegistrar = poParseOptions->poCustomFuncRegistrar; /* -------------------------------------------------------------------- */ /* Identify field information. */ /* -------------------------------------------------------------------- */ for( i = 0; i < result_columns; i++ ) { swq_col_def *def = column_defs + i; if( def->expr != NULL && def->expr->eNodeType != SNT_COLUMN ) { def->field_index = -1; def->table_index = -1; if( def->expr->Check( field_list, TRUE, FALSE, poCustomFuncRegistrar ) == SWQ_ERROR ) return CE_Failure; def->field_type = def->expr->field_type; } else { swq_field_type this_type; /* identify field */ def->field_index = swq_identify_field( def->table_name, def->field_name, field_list, &this_type, &(def->table_index) ); /* record field type */ def->field_type = this_type; if( def->field_index == -1 && def->col_func != SWQCF_COUNT ) { CPLError( CE_Failure, CPLE_AppDefined, "Unrecognised field name %s.", def->table_name[0] ? CPLSPrintf("%s.%s", def->table_name, def->field_name) : def->field_name ); return CE_Failure; } } /* identify column function if present */ if( (def->col_func == SWQCF_MIN || def->col_func == SWQCF_MAX || def->col_func == SWQCF_AVG || def->col_func == SWQCF_SUM) && (def->field_type == SWQ_STRING || def->field_type == SWQ_GEOMETRY) ) { // possibly this is already enforced by the checker? const swq_operation *op = swq_op_registrar::GetOperator( (swq_op) def->col_func ); CPLError( CE_Failure, CPLE_AppDefined, "Use of field function %s() on %s field %s illegal.", op->pszName, SWQFieldTypeToString(def->field_type), def->field_name ); return CE_Failure; } } /* -------------------------------------------------------------------- */ /* Check if we are producing a one row summary result or a set */ /* of records. Generate an error if we get conflicting */ /* indications. */ /* -------------------------------------------------------------------- */ int bAllowDistinctOnMultipleFields = ( poParseOptions && poParseOptions->bAllowDistinctOnMultipleFields ); if( query_mode == SWQM_DISTINCT_LIST && result_columns > 1 && !bAllowDistinctOnMultipleFields ) { CPLError( CE_Failure, CPLE_NotSupported, "SELECT DISTINCT not supported on multiple columns." ); return CE_Failure; } for( i = 0; i < result_columns; i++ ) { swq_col_def *def = column_defs + i; int this_indicator = -1; if( query_mode == SWQM_DISTINCT_LIST && def->field_type == SWQ_GEOMETRY ) { int bAllowDistinctOnGeometryField = ( poParseOptions && poParseOptions->bAllowDistinctOnGeometryField ); if( !bAllowDistinctOnGeometryField ) { CPLError( CE_Failure, CPLE_NotSupported, "SELECT DISTINCT on a geometry not supported." ); return CE_Failure; } } if( def->col_func == SWQCF_MIN || def->col_func == SWQCF_MAX || def->col_func == SWQCF_AVG || def->col_func == SWQCF_SUM || def->col_func == SWQCF_COUNT ) { this_indicator = SWQM_SUMMARY_RECORD; if( def->col_func == SWQCF_COUNT && def->distinct_flag && def->field_type == SWQ_GEOMETRY ) { CPLError( CE_Failure, CPLE_AppDefined, "SELECT COUNT DISTINCT on a geometry not supported." ); return CE_Failure; } } else if( def->col_func == SWQCF_NONE ) { if( query_mode == SWQM_DISTINCT_LIST ) { def->distinct_flag = TRUE; this_indicator = SWQM_DISTINCT_LIST; } else this_indicator = SWQM_RECORDSET; } if( this_indicator != query_mode && this_indicator != -1 && query_mode != 0 ) { CPLError( CE_Failure, CPLE_AppDefined, "Field list implies mixture of regular recordset mode, summary mode or distinct field list mode." ); return CE_Failure; } if( this_indicator != -1 ) query_mode = this_indicator; } if (result_columns == 0) { query_mode = SWQM_RECORDSET; } /* -------------------------------------------------------------------- */ /* Process column names in JOIN specs. */ /* -------------------------------------------------------------------- */ for( i = 0; i < join_count; i++ ) { swq_join_def *def = join_defs + i; if( def->poExpr->Check( field_list, TRUE, TRUE, poCustomFuncRegistrar ) == SWQ_ERROR ) return CE_Failure; if( !CheckCompatibleJoinExpr( def->poExpr, def->secondary_table, field_list ) ) return CE_Failure; } /* -------------------------------------------------------------------- */ /* Process column names in order specs. */ /* -------------------------------------------------------------------- */ for( i = 0; i < order_specs; i++ ) { swq_order_def *def = order_defs + i; /* identify field */ swq_field_type field_type; def->field_index = swq_identify_field( def->table_name, def->field_name, field_list, &field_type, &(def->table_index) ); if( def->field_index == -1 ) { CPLError( CE_Failure, CPLE_AppDefined, "Unrecognised field name %s in ORDER BY.", def->table_name[0] ? CPLSPrintf("%s.%s", def->table_name, def->field_name) : def->field_name ); return CE_Failure; } if( def->table_index != 0 ) { CPLError( CE_Failure, CPLE_AppDefined, "Cannot use field '%s' of a secondary table in a ORDER BY clause", def->field_name ); return CE_Failure; } if( field_type == SWQ_GEOMETRY ) { CPLError( CE_Failure, CPLE_AppDefined, "Cannot use geometry field '%s' in a ORDER BY clause", def->field_name ); return CE_Failure; } } /* -------------------------------------------------------------------- */ /* Post process the where clause, subbing in field indexes and */ /* doing final validation. */ /* -------------------------------------------------------------------- */ int bAllowFieldsInSecondaryTablesInWhere = FALSE; if( poParseOptions != NULL ) bAllowFieldsInSecondaryTablesInWhere = poParseOptions->bAllowFieldsInSecondaryTablesInWhere; if( where_expr != NULL && where_expr->Check( field_list, bAllowFieldsInSecondaryTablesInWhere, FALSE, poCustomFuncRegistrar ) == SWQ_ERROR ) { return CE_Failure; } return CE_None; }
CPLErr swq_select::parse( swq_field_list *field_list, int parse_flags ) { int i; CPLErr eError; eError = expand_wildcard( field_list ); if( eError != CE_None ) return eError; /* -------------------------------------------------------------------- */ /* Identify field information. */ /* -------------------------------------------------------------------- */ for( i = 0; i < result_columns; i++ ) { swq_col_def *def = column_defs + i; if( def->expr != NULL && def->expr->eNodeType != SNT_COLUMN ) { def->field_index = -1; def->table_index = -1; if( def->expr->Check( field_list ) == SWQ_ERROR ) return CE_Failure; def->field_type = def->expr->field_type; // If the field was changed from string constant to // column field then adopt the name. if( def->expr->eNodeType == SNT_COLUMN ) { def->field_index = def->expr->field_index; def->table_index = def->expr->table_index; CPLFree( def->field_name ); def->field_name = CPLStrdup(def->expr->string_value); } } else { swq_field_type this_type; /* identify field */ def->field_index = swq_identify_field( def->field_name, field_list, &this_type, &(def->table_index) ); /* record field type */ def->field_type = this_type; if( def->field_index == -1 && def->col_func != SWQCF_COUNT ) { CPLError( CE_Failure, CPLE_AppDefined, "Unrecognised field name %s.", def->field_name ); return CE_Failure; } } /* identify column function if present */ if( (def->col_func == SWQCF_MIN || def->col_func == SWQCF_MAX || def->col_func == SWQCF_AVG || def->col_func == SWQCF_SUM) && def->field_type == SWQ_STRING ) { // possibly this is already enforced by the checker? const swq_operation *op = swq_op_registrar::GetOperator( (swq_op) def->col_func ); CPLError( CE_Failure, CPLE_AppDefined, "Use of field function %s() on string field %s illegal.", op->osName.c_str(), def->field_name ); return CE_Failure; } } /* -------------------------------------------------------------------- */ /* Check if we are producing a one row summary result or a set */ /* of records. Generate an error if we get conflicting */ /* indications. */ /* -------------------------------------------------------------------- */ query_mode = -1; for( i = 0; i < result_columns; i++ ) { swq_col_def *def = column_defs + i; int this_indicator = -1; if( def->col_func == SWQCF_MIN || def->col_func == SWQCF_MAX || def->col_func == SWQCF_AVG || def->col_func == SWQCF_SUM || def->col_func == SWQCF_COUNT ) this_indicator = SWQM_SUMMARY_RECORD; else if( def->col_func == SWQCF_NONE ) { if( def->distinct_flag ) this_indicator = SWQM_DISTINCT_LIST; else this_indicator = SWQM_RECORDSET; } if( this_indicator != query_mode && this_indicator != -1 && query_mode != -1 ) { CPLError( CE_Failure, CPLE_AppDefined, "Field list implies mixture of regular recordset mode, summary mode or distinct field list mode." ); return CE_Failure; } if( this_indicator != -1 ) query_mode = this_indicator; } if( result_columns > 1 && query_mode == SWQM_DISTINCT_LIST ) { CPLError( CE_Failure, CPLE_AppDefined, "SELECTing more than one DISTINCT field is a query not supported." ); return CE_Failure; } else if (result_columns == 0) { query_mode = SWQM_RECORDSET; } /* -------------------------------------------------------------------- */ /* Process column names in JOIN specs. */ /* -------------------------------------------------------------------- */ for( i = 0; i < join_count; i++ ) { swq_join_def *def = join_defs + i; int table_id; /* identify primary field */ def->primary_field = swq_identify_field( def->primary_field_name, field_list, NULL, &table_id ); if( def->primary_field == -1 ) { CPLError( CE_Failure, CPLE_AppDefined, "Unrecognised primary field %s in JOIN clause..", def->primary_field_name ); return CE_Failure; } if( table_id != 0 ) { CPLError( CE_Failure, CPLE_AppDefined, "Currently the primary key must come from the primary table in\n" "JOIN, %s is not from the primary table.", def->primary_field_name ); return CE_Failure; } /* identify secondary field */ def->secondary_field = swq_identify_field( def->secondary_field_name, field_list, NULL,&table_id); if( def->secondary_field == -1 ) { CPLError( CE_Failure, CPLE_AppDefined, "Unrecognised secondary field %s in JOIN clause..", def->secondary_field_name ); return CE_Failure; } if( table_id != def->secondary_table ) { CPLError( CE_Failure, CPLE_AppDefined, "Currently the secondary key must come from the secondary table\n" "listed in the JOIN. %s is not from table %s..", def->secondary_field_name, table_defs[def->secondary_table].table_name); return CE_Failure; } } /* -------------------------------------------------------------------- */ /* Process column names in order specs. */ /* -------------------------------------------------------------------- */ for( i = 0; i < order_specs; i++ ) { swq_order_def *def = order_defs + i; /* identify field */ def->field_index = swq_identify_field( def->field_name, field_list, NULL, &(def->table_index) ); if( def->field_index == -1 ) { CPLError( CE_Failure, CPLE_AppDefined, "Unrecognised field name %s in ORDER BY.", def->field_name ); return CE_Failure; } } /* -------------------------------------------------------------------- */ /* Post process the where clause, subbing in field indexes and */ /* doing final validation. */ /* -------------------------------------------------------------------- */ if( where_expr != NULL && where_expr->Check( field_list ) == SWQ_ERROR ) { return CE_Failure; } return CE_None; }
swq_field_type swq_expr_node::Check( swq_field_list *poFieldList, int bAllowFieldsInSecondaryTables, int bAllowMismatchTypeOnFieldComparison, swq_custom_func_registrar* poCustomFuncRegistrar, int nDepth ) { if( nDepth == 32 ) { CPLError(CE_Failure, CPLE_AppDefined, "Too many recursion levels in expression"); return SWQ_ERROR; } /* -------------------------------------------------------------------- */ /* Otherwise we take constants literally. */ /* -------------------------------------------------------------------- */ if( eNodeType == SNT_CONSTANT ) return field_type; /* -------------------------------------------------------------------- */ /* If this is intended to be a field definition, but has not */ /* yet been looked up, we do so now. */ /* -------------------------------------------------------------------- */ if( eNodeType == SNT_COLUMN && field_index == -1 ) { field_index = swq_identify_field( table_name, string_value, poFieldList, &field_type, &table_index ); if( field_index < 0 ) { if( table_name ) CPLError( CE_Failure, CPLE_AppDefined, R"("%s"."%s" not recognised as an available field.)", table_name, string_value ); else CPLError( CE_Failure, CPLE_AppDefined, "\"%s\" not recognised as an available field.", string_value ); return SWQ_ERROR; } if( !bAllowFieldsInSecondaryTables && table_index != 0 ) { CPLError( CE_Failure, CPLE_AppDefined, "Cannot use field '%s' of a secondary table in this context", string_value ); return SWQ_ERROR; } } if( eNodeType == SNT_COLUMN ) return field_type; /* -------------------------------------------------------------------- */ /* We are dealing with an operation - fetch the definition. */ /* -------------------------------------------------------------------- */ const swq_operation *poOp = (nOperation == SWQ_CUSTOM_FUNC && poCustomFuncRegistrar != nullptr ) ? poCustomFuncRegistrar->GetOperator(string_value) : swq_op_registrar::GetOperator(static_cast<swq_op>(nOperation)); if( poOp == nullptr ) { if( nOperation == SWQ_CUSTOM_FUNC ) CPLError( CE_Failure, CPLE_AppDefined, "Check(): Unable to find definition for operator %s.", string_value ); else CPLError( CE_Failure, CPLE_AppDefined, "Check(): Unable to find definition for operator %d.", nOperation ); return SWQ_ERROR; } /* -------------------------------------------------------------------- */ /* Check subexpressions first. */ /* -------------------------------------------------------------------- */ for( int i = 0; i < nSubExprCount; i++ ) { if( papoSubExpr[i]->Check(poFieldList, bAllowFieldsInSecondaryTables, bAllowMismatchTypeOnFieldComparison, poCustomFuncRegistrar, nDepth + 1) == SWQ_ERROR ) return SWQ_ERROR; } /* -------------------------------------------------------------------- */ /* Check this node. */ /* -------------------------------------------------------------------- */ field_type = poOp->pfnChecker( this, bAllowMismatchTypeOnFieldComparison ); return field_type; }
swq_field_type swq_expr_node::Check(swq_field_list *poFieldList) { /* -------------------------------------------------------------------- */ /* If something is a string constant, we must check if it is */ /* actually a reference to a field in which case we will */ /* convert it into a column type. */ /* -------------------------------------------------------------------- */ if (eNodeType == SNT_CONSTANT && field_type == SWQ_STRING) { int wrk_field_index, wrk_table_index; swq_field_type wrk_field_type; wrk_field_index = swq_identify_field(string_value, poFieldList, &wrk_field_type, &wrk_table_index); if (wrk_field_index >= 0) { eNodeType = SNT_COLUMN; field_index = -1; table_index = -1; } } /* -------------------------------------------------------------------- */ /* Otherwise we take constants literally. */ /* -------------------------------------------------------------------- */ if (eNodeType == SNT_CONSTANT) return field_type; /* -------------------------------------------------------------------- */ /* If this is intended to be a field definition, but has not */ /* yet been looked up, we do so now. */ /* -------------------------------------------------------------------- */ if (eNodeType == SNT_COLUMN && field_index == -1) { field_index = swq_identify_field(string_value, poFieldList, &field_type, &table_index); if (field_index < 0) { CPLError(CE_Failure, CPLE_AppDefined, "'%s' not recognised as an available field.", string_value); return SWQ_ERROR; } } if (eNodeType == SNT_COLUMN) return field_type; /* -------------------------------------------------------------------- */ /* We are dealing with an operation - fetch the definition. */ /* -------------------------------------------------------------------- */ const swq_operation *poOp = swq_op_registrar::GetOperator((swq_op)nOperation); if (poOp == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "Check(): Unable to find definition for operator %d.", nOperation); return SWQ_ERROR; } /* -------------------------------------------------------------------- */ /* Check subexpressions first. */ /* -------------------------------------------------------------------- */ int i; for (i = 0; i < nSubExprCount; i++) { if (papoSubExpr[i]->Check(poFieldList) == SWQ_ERROR) return SWQ_ERROR; } /* -------------------------------------------------------------------- */ /* Check this node. */ /* -------------------------------------------------------------------- */ field_type = poOp->pfnChecker(this); return field_type; }