swq_field_type SWQGeneralChecker( swq_expr_node *poNode ) { swq_field_type eRetType = SWQ_ERROR; swq_field_type eArgType = SWQ_OTHER; int nArgCount = -1; switch( (swq_op) poNode->nOperation ) { case SWQ_AND: case SWQ_OR: case SWQ_NOT: eRetType = SWQ_BOOLEAN; break; case SWQ_EQ: case SWQ_NE: case SWQ_GT: case SWQ_LT: case SWQ_GE: case SWQ_LE: case SWQ_IN: case SWQ_BETWEEN: eRetType = SWQ_BOOLEAN; SWQAutoPromoteIntegerToFloat( poNode ); SWQAutoPromoteStringToDateTime( poNode ); eArgType = poNode->papoSubExpr[0]->field_type; break; case SWQ_ISNULL: eRetType = SWQ_BOOLEAN; break; case SWQ_LIKE: eRetType = SWQ_BOOLEAN; eArgType = SWQ_STRING; break; case SWQ_MODULUS: eRetType = SWQ_INTEGER; eArgType = SWQ_INTEGER; break; case SWQ_ADD: SWQAutoPromoteIntegerToFloat( poNode ); if( poNode->papoSubExpr[0]->field_type == SWQ_STRING ) eRetType = eArgType = SWQ_STRING; else if( poNode->papoSubExpr[0]->field_type == SWQ_FLOAT ) eRetType = eArgType = SWQ_FLOAT; else eRetType = eArgType = SWQ_INTEGER; break; case SWQ_SUBTRACT: case SWQ_MULTIPLY: case SWQ_DIVIDE: SWQAutoPromoteIntegerToFloat( poNode ); if( poNode->papoSubExpr[0]->field_type == SWQ_FLOAT ) eRetType = eArgType = SWQ_FLOAT; else eRetType = eArgType = SWQ_INTEGER; break; case SWQ_CONCAT: eRetType = SWQ_STRING; eArgType = SWQ_STRING; break; case SWQ_SUBSTR: eRetType = SWQ_STRING; if( poNode->nSubExprCount > 3 || poNode->nSubExprCount < 2 ) { CPLError( CE_Failure, CPLE_AppDefined, "Expected 2 or 3 arguments to SUBSTR(), but got %d.", poNode->nSubExprCount ); return SWQ_ERROR; } if( poNode->papoSubExpr[0]->field_type != SWQ_STRING || poNode->papoSubExpr[1]->field_type != SWQ_INTEGER || (poNode->nSubExprCount > 2 && poNode->papoSubExpr[2]->field_type != SWQ_INTEGER) ) { CPLError( CE_Failure, CPLE_AppDefined, "Wrong argument type for SUBSTR(), expected SUBSTR(string,int,int) or SUBSTR(string,int)." ); return SWQ_ERROR; } break; default: { const swq_operation *poOp = swq_op_registrar::GetOperator((swq_op)poNode->nOperation); CPLError( CE_Failure, CPLE_AppDefined, "SWQGeneralChecker() called on unsupported operation %s.", poOp->osName.c_str()); return SWQ_ERROR; } } /* -------------------------------------------------------------------- */ /* Check argument types. */ /* -------------------------------------------------------------------- */ if( eArgType != SWQ_OTHER ) { int i; if( eArgType == SWQ_INTEGER ) eArgType = SWQ_FLOAT; for( i = 0; i < poNode->nSubExprCount; i++ ) { swq_field_type eThisArgType = poNode->papoSubExpr[i]->field_type; if( eThisArgType == SWQ_INTEGER ) eThisArgType = SWQ_FLOAT; if( eArgType != eThisArgType ) { const swq_operation *poOp = swq_op_registrar::GetOperator((swq_op)poNode->nOperation); CPLError( CE_Failure, CPLE_AppDefined, "Type mismatch or improper type of arguments to %s operator.", poOp->osName.c_str() ); return SWQ_ERROR; } } } /* -------------------------------------------------------------------- */ /* Validate the arg count if requested. */ /* -------------------------------------------------------------------- */ if( nArgCount != -1 && nArgCount != poNode->nSubExprCount ) { const swq_operation *poOp = swq_op_registrar::GetOperator((swq_op)poNode->nOperation); CPLError( CE_Failure, CPLE_AppDefined, "Expected %d arguments to %s, but got %d arguments.", nArgCount, poOp->osName.c_str(), poNode->nSubExprCount ); return SWQ_ERROR; } return eRetType; }
swq_field_type SWQGeneralChecker( swq_expr_node *poNode, int bAllowMismatchTypeOnFieldComparison ) { swq_field_type eRetType = SWQ_ERROR; swq_field_type eArgType = SWQ_OTHER; // int nArgCount = -1; switch( (swq_op) poNode->nOperation ) { case SWQ_AND: case SWQ_OR: case SWQ_NOT: if( !SWQCheckSubExprAreNotGeometries(poNode) ) return SWQ_ERROR; eRetType = SWQ_BOOLEAN; break; case SWQ_EQ: case SWQ_NE: case SWQ_GT: case SWQ_LT: case SWQ_GE: case SWQ_LE: case SWQ_IN: case SWQ_BETWEEN: if( !SWQCheckSubExprAreNotGeometries(poNode) ) return SWQ_ERROR; eRetType = SWQ_BOOLEAN; SWQAutoConvertStringToNumeric( poNode ); SWQAutoPromoteIntegerToInteger64OrFloat( poNode ); SWQAutoPromoteStringToDateTime( poNode ); eArgType = poNode->papoSubExpr[0]->field_type; break; case SWQ_ISNULL: eRetType = SWQ_BOOLEAN; break; case SWQ_LIKE: if( !SWQCheckSubExprAreNotGeometries(poNode) ) return SWQ_ERROR; eRetType = SWQ_BOOLEAN; eArgType = SWQ_STRING; break; case SWQ_MODULUS: if( !SWQCheckSubExprAreNotGeometries(poNode) ) return SWQ_ERROR; eRetType = SWQ_INTEGER; eArgType = SWQ_INTEGER; break; case SWQ_ADD: if( !SWQCheckSubExprAreNotGeometries(poNode) ) return SWQ_ERROR; SWQAutoPromoteIntegerToInteger64OrFloat( poNode ); if( poNode->papoSubExpr[0]->field_type == SWQ_STRING ) eRetType = eArgType = SWQ_STRING; else if( poNode->papoSubExpr[0]->field_type == SWQ_FLOAT ) eRetType = eArgType = SWQ_FLOAT; else if( poNode->papoSubExpr[0]->field_type == SWQ_INTEGER64 ) eRetType = eArgType = SWQ_INTEGER64; else eRetType = eArgType = SWQ_INTEGER; break; case SWQ_SUBTRACT: case SWQ_MULTIPLY: case SWQ_DIVIDE: if( !SWQCheckSubExprAreNotGeometries(poNode) ) return SWQ_ERROR; SWQAutoPromoteIntegerToInteger64OrFloat( poNode ); if( poNode->papoSubExpr[0]->field_type == SWQ_FLOAT ) eRetType = eArgType = SWQ_FLOAT; else if( poNode->papoSubExpr[0]->field_type == SWQ_INTEGER64 ) eRetType = eArgType = SWQ_INTEGER64; else eRetType = eArgType = SWQ_INTEGER; break; case SWQ_CONCAT: if( !SWQCheckSubExprAreNotGeometries(poNode) ) return SWQ_ERROR; eRetType = SWQ_STRING; eArgType = SWQ_STRING; break; case SWQ_SUBSTR: if( !SWQCheckSubExprAreNotGeometries(poNode) ) return SWQ_ERROR; eRetType = SWQ_STRING; if( poNode->nSubExprCount > 3 || poNode->nSubExprCount < 2 ) { CPLError( CE_Failure, CPLE_AppDefined, "Expected 2 or 3 arguments to SUBSTR(), but got %d.", poNode->nSubExprCount ); return SWQ_ERROR; } if( poNode->papoSubExpr[0]->field_type != SWQ_STRING || poNode->papoSubExpr[1]->field_type != SWQ_INTEGER || (poNode->nSubExprCount > 2 && poNode->papoSubExpr[2]->field_type != SWQ_INTEGER) ) { CPLError( CE_Failure, CPLE_AppDefined, "Wrong argument type for SUBSTR(), expected SUBSTR(string,int,int) or SUBSTR(string,int)." ); return SWQ_ERROR; } break; case SWQ_HSTORE_GET_VALUE: if( !SWQCheckSubExprAreNotGeometries(poNode) ) return SWQ_ERROR; eRetType = SWQ_STRING; if( poNode->nSubExprCount != 2 ) { CPLError( CE_Failure, CPLE_AppDefined, "Expected 2 arguments to hstore_get_value(), but got %d.", poNode->nSubExprCount ); return SWQ_ERROR; } if( poNode->papoSubExpr[0]->field_type != SWQ_STRING || poNode->papoSubExpr[1]->field_type != SWQ_STRING ) { CPLError( CE_Failure, CPLE_AppDefined, "Wrong argument type for hstore_get_value(), expected hstore_get_value(string,string)." ); return SWQ_ERROR; } break; default: { const swq_operation *poOp = swq_op_registrar::GetOperator((swq_op)poNode->nOperation); CPLError( CE_Failure, CPLE_AppDefined, "SWQGeneralChecker() called on unsupported operation %s.", poOp->pszName); return SWQ_ERROR; } } /* -------------------------------------------------------------------- */ /* Check argument types. */ /* -------------------------------------------------------------------- */ if( eArgType != SWQ_OTHER ) { if( SWQ_IS_INTEGER(eArgType) || eArgType == SWQ_BOOLEAN ) eArgType = SWQ_FLOAT; for( int i = 0; i < poNode->nSubExprCount; i++ ) { swq_field_type eThisArgType = poNode->papoSubExpr[i]->field_type; if( SWQ_IS_INTEGER(eThisArgType) || eThisArgType == SWQ_BOOLEAN ) eThisArgType = SWQ_FLOAT; if( eArgType != eThisArgType ) { // Convenience for join. We allow comparing numeric columns // and string columns, by casting string columns to numeric if( bAllowMismatchTypeOnFieldComparison && poNode->nSubExprCount == 2 && poNode->nOperation == SWQ_EQ && poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN && poNode->papoSubExpr[i]->eNodeType == SNT_COLUMN && eArgType == SWQ_FLOAT && eThisArgType == SWQ_STRING ) { swq_expr_node* poNewNode = new swq_expr_node(SWQ_CAST); poNewNode->PushSubExpression(poNode->papoSubExpr[i]); poNewNode->PushSubExpression(new swq_expr_node("FLOAT")); SWQCastChecker(poNewNode, FALSE); poNode->papoSubExpr[i] = poNewNode; break; } if( bAllowMismatchTypeOnFieldComparison && poNode->nSubExprCount == 2 && poNode->nOperation == SWQ_EQ && poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN && poNode->papoSubExpr[i]->eNodeType == SNT_COLUMN && eThisArgType == SWQ_FLOAT && eArgType == SWQ_STRING ) { swq_expr_node* poNewNode = new swq_expr_node(SWQ_CAST); poNewNode->PushSubExpression(poNode->papoSubExpr[0]); poNewNode->PushSubExpression(new swq_expr_node("FLOAT")); SWQCastChecker(poNewNode, FALSE); poNode->papoSubExpr[0] = poNewNode; break; } const swq_operation *poOp = swq_op_registrar::GetOperator((swq_op)poNode->nOperation); CPLError( CE_Failure, CPLE_AppDefined, "Type mismatch or improper type of arguments to %s operator.", poOp->pszName ); return SWQ_ERROR; } } } /* -------------------------------------------------------------------- */ /* Validate the arg count if requested. */ /* -------------------------------------------------------------------- */ #if 0 // nArgCount was always -1, so this block was never executed. if( nArgCount != -1 && nArgCount != poNode->nSubExprCount ) { const swq_operation *poOp = swq_op_registrar::GetOperator((swq_op)poNode->nOperation); CPLError( CE_Failure, CPLE_AppDefined, "Expected %d arguments to %s, but got %d arguments.", nArgCount, poOp->pszName, poNode->nSubExprCount ); return SWQ_ERROR; } #endif return eRetType; }