static void SWQAutoConvertStringToNumeric( swq_expr_node *poNode ) { if( poNode->nSubExprCount < 2 ) return; swq_field_type eArgType = poNode->papoSubExpr[0]->field_type; int i; for( i = 1; i < poNode->nSubExprCount; i++ ) { swq_expr_node *poSubNode = poNode->papoSubExpr[i]; /* identify the mixture of the argument type */ if( (eArgType == SWQ_STRING && (SWQ_IS_INTEGER(poSubNode->field_type) || poSubNode->field_type == SWQ_FLOAT)) || (SWQ_IS_INTEGER(eArgType) && poSubNode->field_type == SWQ_STRING) ) { eArgType = SWQ_FLOAT; break; } } for( i = 0; i < poNode->nSubExprCount; i++ ) { swq_expr_node *poSubNode = poNode->papoSubExpr[i]; if( eArgType == SWQ_FLOAT && poSubNode->field_type == SWQ_STRING ) { if( poSubNode->eNodeType == SNT_CONSTANT ) { /* apply the string to numeric conversion */ char* endPtr = NULL; poSubNode->float_value = CPLStrtod(poSubNode->string_value, &endPtr); if ( !(endPtr == NULL || *endPtr == '\0') ) { CPLError(CE_Warning, CPLE_NotSupported, "Conversion failed when converting the string value '%s' to data type float.", poSubNode->string_value); continue; } /* we should also fill the integer value in this case */ poSubNode->int_value = (GIntBig)poSubNode->float_value; poSubNode->field_type = SWQ_FLOAT; } } } }
static void SWQAutoPromoteIntegerToInteger64OrFloat( swq_expr_node *poNode ) { if( poNode->nSubExprCount < 2 ) return; swq_field_type eArgType = poNode->papoSubExpr[0]->field_type; int i; // We allow mixes of integer, integer64 and float, and string and dates. // When encountered, we promote integers/integer64 to floats, // integer to integer64 and strings to dates. We do that now. for( i = 1; i < poNode->nSubExprCount; i++ ) { swq_expr_node *poSubNode = poNode->papoSubExpr[i]; if( SWQ_IS_INTEGER(eArgType) && poSubNode->field_type == SWQ_FLOAT ) eArgType = SWQ_FLOAT; else if( eArgType == SWQ_INTEGER && poSubNode->field_type == SWQ_INTEGER64 ) eArgType = SWQ_INTEGER64; } for( i = 0; i < poNode->nSubExprCount; i++ ) { swq_expr_node *poSubNode = poNode->papoSubExpr[i]; if( eArgType == SWQ_FLOAT && SWQ_IS_INTEGER(poSubNode->field_type) ) { if( poSubNode->eNodeType == SNT_CONSTANT ) { poSubNode->float_value = (double) poSubNode->int_value; poSubNode->field_type = SWQ_FLOAT; } } else if( eArgType == SWQ_INTEGER64 && poSubNode->field_type == SWQ_INTEGER ) { if( poSubNode->eNodeType == SNT_CONSTANT ) { poSubNode->field_type = SWQ_INTEGER64; } } } }
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; }
swq_expr_node *SWQGeneralEvaluator( swq_expr_node *node, swq_expr_node **sub_node_values ) { swq_expr_node *poRet = NULL; /* -------------------------------------------------------------------- */ /* Floating point operations. */ /* -------------------------------------------------------------------- */ if( sub_node_values[0]->field_type == SWQ_FLOAT || (node->nSubExprCount > 1 && sub_node_values[1]->field_type == SWQ_FLOAT) ) { poRet = new swq_expr_node(0); poRet->field_type = node->field_type; if( SWQ_IS_INTEGER(sub_node_values[0]->field_type) ) sub_node_values[0]->float_value = (double) sub_node_values[0]->int_value; if( node->nSubExprCount > 1 && SWQ_IS_INTEGER(sub_node_values[1]->field_type) ) sub_node_values[1]->float_value = (double)sub_node_values[1]->int_value; if( node->nOperation != SWQ_ISNULL ) { for( int i = 0; i < node->nSubExprCount; i++ ) { if( sub_node_values[i]->is_null ) { if( poRet->field_type == SWQ_BOOLEAN ) { poRet->int_value = FALSE; return poRet; } else if( poRet->field_type == SWQ_FLOAT ) { poRet->float_value = 0; poRet->is_null = 1; return poRet; } else if( SWQ_IS_INTEGER(poRet->field_type) || node->nOperation == SWQ_MODULUS ) { poRet->field_type = SWQ_INTEGER; poRet->int_value = 0; poRet->is_null = 1; return poRet; } } } } switch( (swq_op) node->nOperation ) { case SWQ_EQ: poRet->int_value = sub_node_values[0]->float_value == sub_node_values[1]->float_value; break; case SWQ_NE: poRet->int_value = sub_node_values[0]->float_value != sub_node_values[1]->float_value; break; case SWQ_GT: poRet->int_value = sub_node_values[0]->float_value > sub_node_values[1]->float_value; break; case SWQ_LT: poRet->int_value = sub_node_values[0]->float_value < sub_node_values[1]->float_value; break; case SWQ_GE: poRet->int_value = sub_node_values[0]->float_value >= sub_node_values[1]->float_value; break; case SWQ_LE: poRet->int_value = sub_node_values[0]->float_value <= sub_node_values[1]->float_value; break; case SWQ_IN: { poRet->int_value = 0; for( int i = 1; i < node->nSubExprCount; i++ ) { if( sub_node_values[0]->float_value == sub_node_values[i]->float_value ) { poRet->int_value = 1; break; } } } break; case SWQ_BETWEEN: poRet->int_value = sub_node_values[0]->float_value >= sub_node_values[1]->float_value && sub_node_values[0]->float_value <= sub_node_values[2]->float_value; break; case SWQ_ISNULL: poRet->int_value = sub_node_values[0]->is_null; break; case SWQ_ADD: poRet->float_value = sub_node_values[0]->float_value + sub_node_values[1]->float_value; break; case SWQ_SUBTRACT: poRet->float_value = sub_node_values[0]->float_value - sub_node_values[1]->float_value; break; case SWQ_MULTIPLY: poRet->float_value = sub_node_values[0]->float_value * sub_node_values[1]->float_value; break; case SWQ_DIVIDE: if( sub_node_values[1]->float_value == 0 ) poRet->float_value = INT_MAX; else poRet->float_value = sub_node_values[0]->float_value / sub_node_values[1]->float_value; break; case SWQ_MODULUS: { GIntBig nRight = (GIntBig) sub_node_values[1]->float_value; poRet->field_type = SWQ_INTEGER; if (nRight == 0) poRet->int_value = INT_MAX; else poRet->int_value = ((GIntBig) sub_node_values[0]->float_value) % nRight; break; } default: CPLAssert( false ); delete poRet; poRet = NULL; break; } } /* -------------------------------------------------------------------- */ /* integer/boolean operations. */ /* -------------------------------------------------------------------- */ else if( SWQ_IS_INTEGER(sub_node_values[0]->field_type) || sub_node_values[0]->field_type == SWQ_BOOLEAN ) { poRet = new swq_expr_node(0); poRet->field_type = node->field_type; if( node->nOperation != SWQ_ISNULL ) { for( int i = 0; i < node->nSubExprCount; i++ ) { if( sub_node_values[i]->is_null ) { if( poRet->field_type == SWQ_BOOLEAN ) { poRet->int_value = FALSE; return poRet; } else if( SWQ_IS_INTEGER(poRet->field_type) ) { poRet->int_value = 0; poRet->is_null = 1; return poRet; } } } } switch( (swq_op) node->nOperation ) { case SWQ_AND: poRet->int_value = sub_node_values[0]->int_value && sub_node_values[1]->int_value; break; case SWQ_OR: poRet->int_value = sub_node_values[0]->int_value || sub_node_values[1]->int_value; break; case SWQ_NOT: poRet->int_value = !sub_node_values[0]->int_value; break; case SWQ_EQ: poRet->int_value = sub_node_values[0]->int_value == sub_node_values[1]->int_value; break; case SWQ_NE: poRet->int_value = sub_node_values[0]->int_value != sub_node_values[1]->int_value; break; case SWQ_GT: poRet->int_value = sub_node_values[0]->int_value > sub_node_values[1]->int_value; break; case SWQ_LT: poRet->int_value = sub_node_values[0]->int_value < sub_node_values[1]->int_value; break; case SWQ_GE: poRet->int_value = sub_node_values[0]->int_value >= sub_node_values[1]->int_value; break; case SWQ_LE: poRet->int_value = sub_node_values[0]->int_value <= sub_node_values[1]->int_value; break; case SWQ_IN: { poRet->int_value = 0; for( int i = 1; i < node->nSubExprCount; i++ ) { if( sub_node_values[0]->int_value == sub_node_values[i]->int_value ) { poRet->int_value = 1; break; } } } break; case SWQ_BETWEEN: poRet->int_value = sub_node_values[0]->int_value >= sub_node_values[1]->int_value && sub_node_values[0]->int_value <= sub_node_values[2]->int_value; break; case SWQ_ISNULL: poRet->int_value = sub_node_values[0]->is_null; break; case SWQ_ADD: poRet->int_value = sub_node_values[0]->int_value + sub_node_values[1]->int_value; break; case SWQ_SUBTRACT: poRet->int_value = sub_node_values[0]->int_value - sub_node_values[1]->int_value; break; case SWQ_MULTIPLY: poRet->int_value = sub_node_values[0]->int_value * sub_node_values[1]->int_value; break; case SWQ_DIVIDE: if( sub_node_values[1]->int_value == 0 ) poRet->int_value = INT_MAX; else poRet->int_value = sub_node_values[0]->int_value / sub_node_values[1]->int_value; break; case SWQ_MODULUS: if( sub_node_values[1]->int_value == 0 ) poRet->int_value = INT_MAX; else poRet->int_value = sub_node_values[0]->int_value % sub_node_values[1]->int_value; break; default: CPLAssert( false ); delete poRet; poRet = NULL; break; } } /* -------------------------------------------------------------------- */ /* String operations. */ /* -------------------------------------------------------------------- */ else { poRet = new swq_expr_node(0); poRet->field_type = node->field_type; if( node->nOperation != SWQ_ISNULL ) { for( int i = 0; i < node->nSubExprCount; i++ ) { if( sub_node_values[i]->is_null ) { if( poRet->field_type == SWQ_BOOLEAN ) { poRet->int_value = FALSE; return poRet; } else if( poRet->field_type == SWQ_STRING ) { poRet->string_value = CPLStrdup(""); poRet->is_null = 1; return poRet; } } } } switch( (swq_op) node->nOperation ) { case SWQ_EQ: { /* When comparing timestamps, the +00 at the end might be discarded */ /* if the other member has no explicit timezone */ if( (sub_node_values[0]->field_type == SWQ_TIMESTAMP || sub_node_values[0]->field_type == SWQ_STRING) && (sub_node_values[1]->field_type == SWQ_TIMESTAMP || sub_node_values[1]->field_type == SWQ_STRING) && strlen(sub_node_values[0]->string_value) > 3 && strlen(sub_node_values[1]->string_value) > 3 && (strcmp(sub_node_values[0]->string_value + strlen(sub_node_values[0]->string_value)-3, "+00") == 0 && sub_node_values[1]->string_value[strlen(sub_node_values[1]->string_value)-3] == ':') ) { poRet->int_value = EQUALN(sub_node_values[0]->string_value, sub_node_values[1]->string_value, strlen(sub_node_values[1]->string_value)); } else if( (sub_node_values[0]->field_type == SWQ_TIMESTAMP || sub_node_values[0]->field_type == SWQ_STRING) && (sub_node_values[1]->field_type == SWQ_TIMESTAMP || sub_node_values[1]->field_type == SWQ_STRING) && strlen(sub_node_values[0]->string_value) > 3 && strlen(sub_node_values[1]->string_value) > 3 && (sub_node_values[0]->string_value[strlen(sub_node_values[0]->string_value)-3] == ':') && strcmp(sub_node_values[1]->string_value + strlen(sub_node_values[1]->string_value)-3, "+00") == 0) { poRet->int_value = EQUALN(sub_node_values[0]->string_value, sub_node_values[1]->string_value, strlen(sub_node_values[0]->string_value)); } else { poRet->int_value = strcasecmp(sub_node_values[0]->string_value, sub_node_values[1]->string_value) == 0; } break; } case SWQ_NE: poRet->int_value = strcasecmp(sub_node_values[0]->string_value, sub_node_values[1]->string_value) != 0; break; case SWQ_GT: poRet->int_value = strcasecmp(sub_node_values[0]->string_value, sub_node_values[1]->string_value) > 0; break; case SWQ_LT: poRet->int_value = strcasecmp(sub_node_values[0]->string_value, sub_node_values[1]->string_value) < 0; break; case SWQ_GE: poRet->int_value = strcasecmp(sub_node_values[0]->string_value, sub_node_values[1]->string_value) >= 0; break; case SWQ_LE: poRet->int_value = strcasecmp(sub_node_values[0]->string_value, sub_node_values[1]->string_value) <= 0; break; case SWQ_IN: { poRet->int_value = 0; for( int i = 1; i < node->nSubExprCount; i++ ) { if( strcasecmp(sub_node_values[0]->string_value, sub_node_values[i]->string_value) == 0 ) { poRet->int_value = 1; break; } } } break; case SWQ_BETWEEN: poRet->int_value = strcasecmp(sub_node_values[0]->string_value, sub_node_values[1]->string_value) >= 0 && strcasecmp(sub_node_values[0]->string_value, sub_node_values[2]->string_value) <= 0; break; case SWQ_LIKE: { char chEscape = '\0'; if( node->nSubExprCount == 3 ) chEscape = sub_node_values[2]->string_value[0]; poRet->int_value = swq_test_like(sub_node_values[0]->string_value, sub_node_values[1]->string_value, chEscape); break; } case SWQ_ISNULL: poRet->int_value = sub_node_values[0]->is_null; break; case SWQ_CONCAT: case SWQ_ADD: { CPLString osResult = sub_node_values[0]->string_value; for( int i = 1; i < node->nSubExprCount; i++ ) osResult += sub_node_values[i]->string_value; poRet->string_value = CPLStrdup(osResult); poRet->is_null = sub_node_values[0]->is_null; break; } case SWQ_SUBSTR: { int nOffset, nSize; const char *pszSrcStr = sub_node_values[0]->string_value; if( SWQ_IS_INTEGER(sub_node_values[1]->field_type) ) nOffset = (int)sub_node_values[1]->int_value; else if( sub_node_values[1]->field_type == SWQ_FLOAT ) nOffset = (int) sub_node_values[1]->float_value; else nOffset = 0; if( node->nSubExprCount < 3 ) nSize = 100000; else if( SWQ_IS_INTEGER(sub_node_values[2]->field_type) ) nSize = (int)sub_node_values[2]->int_value; else if( sub_node_values[2]->field_type == SWQ_FLOAT ) nSize = (int) sub_node_values[2]->float_value; else nSize = 0; int nSrcStrLen = (int)strlen(pszSrcStr); /* In SQL, the first character is at offset 1 */ /* And 0 is considered as 1 */ if (nOffset > 0) nOffset --; /* Some implementations allow negative offsets, to start */ /* from the end of the string */ else if( nOffset < 0 ) { if( nSrcStrLen + nOffset >= 0 ) nOffset = nSrcStrLen + nOffset; else nOffset = 0; } if( nSize < 0 || nOffset > nSrcStrLen ) { nOffset = 0; nSize = 0; } else if( nOffset + nSize > nSrcStrLen ) nSize = nSrcStrLen - nOffset; CPLString osResult = pszSrcStr + nOffset; if( (int)osResult.size() > nSize ) osResult.resize( nSize ); poRet->string_value = CPLStrdup(osResult); poRet->is_null = sub_node_values[0]->is_null; break; } case SWQ_HSTORE_GET_VALUE: { const char *pszHStore = sub_node_values[0]->string_value; const char *pszSearchedKey = sub_node_values[1]->string_value; char* pszRet = OGRHStoreGetValue(pszHStore, pszSearchedKey); poRet->string_value = pszRet ? pszRet : CPLStrdup(""); poRet->is_null = (pszRet == NULL); break; } default: CPLAssert( false ); delete poRet; poRet = NULL; break; } } return poRet; }