| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include <stdlib.h> |
| #include "postgres.h" |
| #include "fmgr.h" |
| #include "cdb/cdbvars.h" |
| #include "resourcemanager/errorcode.h" |
| #include "resourceenforcer/resourceenforcer_simpstring.h" |
| |
| /* |
| * GSimpArray implementation |
| */ |
| |
| /* create simple array */ |
| GSimpArrayPtr createGSimpArray(void) |
| { |
| GSimpArrayPtr sap = (GSimpArrayPtr)malloc(sizeof(GSimpArray)); |
| |
| if ( sap == NULL ) |
| { |
| write_log("Function createGSimpArray out of memory"); |
| return NULL; |
| } |
| |
| sap->Array = NULL; |
| sap->Len = -1; |
| |
| return sap; |
| } |
| |
| /* initialize simple array */ |
| void initGSimpArray(GSimpArrayPtr sap) |
| { |
| Assert( sap != NULL ); |
| |
| sap->Array = NULL; |
| sap->Len = -1; |
| } |
| |
| /* set value for simple array */ |
| int setGSimpArrayWithContent(GSimpArrayPtr sap, char *content, int length) |
| { |
| Assert( sap != NULL ); |
| |
| if ( sap->Array == NULL ) |
| { |
| sap->Array = (char *)malloc(length+1); |
| } |
| else if ( sap->Len < length ) |
| { |
| free(sap->Array); |
| sap->Array = (char *)malloc(length+1); |
| } |
| |
| if ( sap->Array == NULL ) |
| { |
| write_log("Function setGSimpArrayWithContent out of memory"); |
| return UTIL_SIMPSTRING_OUT_OF_MEMORY; |
| } |
| |
| memcpy(sap->Array, content, length); |
| sap->Len = length; |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| void setGSimpArrayWithRef(GSimpArrayPtr sap, char *content, int length) |
| { |
| Assert( sap != NULL ); |
| |
| sap->Array = content; |
| sap->Len = length; |
| } |
| |
| /* free simple array with allocated content. */ |
| void freeGSimpArrayContent(GSimpArrayPtr sap) |
| { |
| Assert( sap != NULL ); |
| |
| if ( sap->Array != NULL ) |
| { |
| free(sap->Array); |
| } |
| |
| sap->Array = NULL; |
| sap->Len = -1; |
| } |
| |
| /* simple array comparison function */ |
| int GSimpArrayComp(GSimpArrayPtr sap1, GSimpArrayPtr sap2) |
| { |
| int val = 0; |
| |
| for ( int i = 0 ; i < sap1->Len && i < sap2->Len ; ++i ) |
| { |
| val = (uint8_t)sap1->Array[i] - (uint8_t)sap2->Array[i]; |
| |
| if ( val != 0 ) |
| { |
| return val; |
| } |
| } |
| |
| return (sap1->Len - sap2->Len); |
| } |
| |
| |
| |
| /* |
| * GSimpString implementation |
| */ |
| |
| GSimpStringPtr createGSimpString(void) |
| { |
| GSimpStringPtr ssp = (GSimpStringPtr)malloc(sizeof(GSimpString)); |
| |
| if ( ssp == NULL ) |
| { |
| write_log("Function createGSimpString out of memory"); |
| return NULL; |
| } |
| |
| ssp->Str = NULL; |
| ssp->Len = -1; |
| |
| return ssp; |
| } |
| |
| void initGSimpString(GSimpStringPtr ssp) |
| { |
| Assert( ssp != NULL ); |
| |
| ssp->Str = NULL; |
| ssp->Len = -1; |
| } |
| |
| void initGSimpStringWithContent(GSimpStringPtr ssp, char *content, int length) |
| { |
| Assert( ssp != NULL ); |
| |
| setGSimpStringWithContent( ssp, content, length); |
| } |
| |
| void initGSimpStringFilled(GSimpStringPtr ssp, uint8_t val, int length) |
| { |
| Assert( ssp != NULL ); |
| |
| setGSimpStringFilled( ssp, val, length); |
| } |
| |
| int setGSimpStringWithContent(GSimpStringPtr ssp, char *content, int length) |
| { |
| Assert( ssp != NULL ); |
| |
| if ( ssp->Str == NULL ) |
| { |
| ssp->Str = (char *)malloc(length+1); |
| } |
| else if ( ssp->Len < length ) |
| { |
| free(ssp->Str); |
| |
| ssp->Str = (char *)malloc(length+1); |
| } |
| |
| if ( ssp->Str == NULL ) |
| { |
| write_log("Function setGSimpStringWithContent out of memory"); |
| return UTIL_SIMPSTRING_OUT_OF_MEMORY; |
| } |
| |
| memcpy(ssp->Str, content, length); |
| ssp->Str[length] = '\0'; |
| ssp->Len = length; |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| int setGSimpStringFilled(GSimpStringPtr ssp, uint8_t val, int length) |
| { |
| Assert( ssp != NULL ); |
| |
| ssp->Str = (char *)malloc(length+1); |
| |
| if ( ssp->Str == NULL ) |
| { |
| write_log("Function setGSimpStringFilled out of memory"); |
| return UTIL_SIMPSTRING_OUT_OF_MEMORY; |
| } |
| |
| memset(ssp->Str, val, length); |
| ssp->Len = length; |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| void freeGSimpStringContent(GSimpStringPtr ssp) |
| { |
| Assert( ssp != NULL ); |
| |
| if ( ssp->Str != NULL ) |
| { |
| free(ssp->Str); |
| } |
| |
| ssp->Str = NULL; |
| ssp->Len = -1; |
| } |
| |
| void setGSimpStringWithRef(GSimpStringPtr ssp, char *content, int length) |
| { |
| Assert( ssp != NULL ); |
| |
| ssp->Str = content; |
| ssp->Len = length; |
| } |
| |
| void clearGSimpStringRef(GSimpStringPtr ssp) |
| { |
| Assert( ssp != NULL ); |
| |
| ssp->Str = NULL; |
| ssp->Len = -1; |
| } |
| |
| int GSimpStringFind(GSimpStringPtr ssp, char *target) |
| { |
| Assert( ssp != NULL ); |
| Assert( target ); |
| |
| if ( ssp->Str == NULL ) |
| { |
| return -1; |
| } |
| |
| char *res = strstr(ssp->Str, target); |
| |
| if ( res == NULL ) |
| { |
| return -1; |
| } |
| |
| return res-(ssp->Str); |
| } |
| |
| int GSimpStringComp(GSimpStringPtr ssp, char *target) |
| { |
| Assert( ssp != NULL ); |
| |
| return strcmp(ssp->Str, target); |
| } |
| |
| int GSimpStringCaseComp(GSimpStringPtr ssp, char *target) |
| { |
| Assert( ssp != NULL ); |
| |
| return strcasecmp(ssp->Str, target); |
| } |
| |
| void GSimpStringCopy(GSimpStringPtr ssp, GSimpStringPtr source) |
| { |
| Assert( ssp != NULL ); |
| Assert( source != NULL ); |
| |
| setGSimpStringWithContent(ssp, source->Str, source->Len); |
| } |
| |
| bool GSimpStringEmpty(GSimpStringPtr ssp) |
| { |
| return ssp->Len == 0; |
| } |
| |
| int GSimpStringSubstring(GSimpStringPtr ssp, |
| int start, |
| int end, |
| GSimpStringPtr target) |
| { |
| Assert( ssp != NULL ); |
| Assert( target != NULL ); |
| |
| /* If end == -1, the substring ends till the end of source string. */ |
| Assert( start >= 0 && ((end > 0 && end > start) || (end == -1))); |
| |
| int newlen = end == -1 ? (ssp->Len)-start : end-start; |
| |
| /* Check and alloc target string space. */ |
| setGSimpStringWithContent( target, |
| (ssp->Str)+start, |
| newlen); |
| |
| return newlen; |
| } |
| |
| int deserializeToGSimpString(GSimpStringPtr ssp, char *content, int *value) |
| { |
| Assert( ssp ); |
| Assert( content ); |
| Assert( value ); |
| |
| ssp->Len = *((int32_t *)content); |
| ssp->Str = (char *)malloc(ssp->Len+1); |
| |
| if ( ssp->Str == NULL ) |
| { |
| write_log("Function deserializeToGSimpString out of memory"); |
| return UTIL_SIMPSTRING_OUT_OF_MEMORY; |
| } |
| |
| memcpy(ssp->Str, content+4, ssp->Len); |
| |
| *value = __SIZE_ALIGN64(ssp->Len + sizeof(int32_t)); |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| int serializeFromGSimpString(GSimpStringPtr ssp, char *content, int *value) |
| { |
| Assert( ssp ); |
| Assert( content ); |
| Assert( value ); |
| |
| *((int32_t *)content) = ssp->Len; |
| memcpy(content+4, ssp->Str, ssp->Len); |
| |
| *value = __SIZE_ALIGN64(ssp->Len + sizeof(int32_t)); |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| int serializeSizeGSimpString(GSimpStringPtr ssp, int *value) |
| { |
| Assert( ssp ); |
| Assert( value ); |
| |
| *value = __SIZE_ALIGN64(ssp->Len + sizeof(int32_t)); |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| bool GSimpStringIsPercentage(GSimpStringPtr ssp) |
| { |
| Assert( ssp ); |
| |
| if ( ssp->Len <= 1 ) |
| { |
| return false; |
| } |
| |
| if ( ssp->Str[strlen(ssp->Str)-1] == '%' ) |
| { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| int GSimpStringToPercentage(GSimpStringPtr ssp, int8_t *value) |
| { |
| Assert( ssp ); |
| Assert( value ); |
| |
| int val; |
| |
| if (sscanf(ssp->Str,"%d%%", &val) == 1 && |
| val >= 0 && |
| val <= 100 ) |
| { |
| *value = val; |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| return UTIL_SIMPSTRING_WRONG_FORMAT; |
| } |
| |
| int GSimpStringToStorageSizeMB(GSimpStringPtr ssp, int32_t *value) |
| { |
| Assert( ssp ); |
| Assert( value ); |
| |
| int tail = strlen(ssp->Str) - 1; |
| int scanres = -1; |
| int32_t val; |
| char buff[256]; |
| |
| if ( tail < 2 || tail > sizeof(buff)-1 ) |
| { |
| return UTIL_SIMPSTRING_WRONG_FORMAT; |
| } |
| |
| strncpy(buff, ssp->Str, tail-1); |
| buff[tail-1] = '\0'; |
| |
| scanres = sscanf(buff, "%d", &val); |
| if ( scanres != 1 ) |
| { |
| return UTIL_SIMPSTRING_WRONG_FORMAT; |
| } |
| |
| if ( (ssp->Str[tail] == 'b' || ssp->Str[tail] == 'B' ) && |
| (ssp->Str[tail-1] == 'm' || ssp->Str[tail-1] == 'M') ) |
| { |
| *value = val; |
| } |
| else if ( (ssp->Str[tail] == 'b' || ssp->Str[tail] == 'B' ) && |
| (ssp->Str[tail-1] == 'g' || ssp->Str[tail-1] == 'G') ) |
| { |
| *value = val * 1024; /* GB to MB */ |
| } |
| else if ( (ssp->Str[tail] == 'b' || ssp->Str[tail] == 'B' ) && |
| (ssp->Str[tail-1] == 't' || ssp->Str[tail-1] == 'T') ) |
| { |
| *value = val * 1024 * 1024; /* TB to MB */ |
| } |
| else |
| { |
| return UTIL_SIMPSTRING_WRONG_FORMAT; |
| } |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| int GSimpStringToMapIndexInt8(GSimpStringPtr ssp, |
| char *strlist, |
| int listsize, |
| int valuewidth, |
| int8_t *result) |
| { |
| Assert( ssp ); |
| Assert( strlist ); |
| Assert( result ); |
| |
| for ( int i = 0 ; i < listsize && i < 127 ; ++i ) |
| { |
| if ( GSimpStringComp(ssp, strlist + i * valuewidth) == 0 ) |
| { |
| *result = i & 0xFF; |
| |
| return FUNC_RETURN_OK; |
| } |
| } |
| |
| *result = -1; |
| |
| return UTIL_SIMPSTR_NO_MATCH; |
| } |
| |
| int GSimpStringToBool(GSimpStringPtr ssp, bool *value) |
| { |
| Assert( ssp ); |
| Assert( value ); |
| |
| if ( strcmp(ssp->Str, "false") == 0 || |
| strcmp(ssp->Str, "FALSE") == 0) |
| { |
| *value = false; |
| } |
| else if ( strcmp(ssp->Str, "true") == 0 || |
| strcmp(ssp->Str, "TRUE") == 0) |
| { |
| *value = true; |
| } |
| else |
| { |
| return UTIL_SIMPSTRING_WRONG_FORMAT; |
| } |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| int GSimpStringToInt8(GSimpStringPtr ssp, int8_t *value) |
| { |
| Assert( ssp ); |
| Assert( value ); |
| |
| int val; |
| int scanres = sscanf(ssp->Str, "%d", &val); |
| |
| if ( scanres == 1 && val >= -128 && val <= 127 ) |
| { |
| *value = val; |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| return UTIL_SIMPSTRING_WRONG_FORMAT; |
| |
| } |
| |
| int GSimpStringToInt32(GSimpStringPtr ssp, int32_t *value) |
| { |
| Assert( ssp ); |
| Assert( value ); |
| |
| int32_t val; |
| int scanres = sscanf(ssp->Str, "%d", &val); |
| |
| if ( scanres == 1 ) |
| { |
| *value = val; |
| return FUNC_RETURN_OK; |
| } |
| |
| return UTIL_SIMPSTRING_WRONG_FORMAT; |
| } |
| |
| int GSimpStringToUInt32(GSimpStringPtr ssp, uint32_t *value) |
| { |
| Assert( ssp ); |
| Assert( value ); |
| |
| uint32_t val; |
| int scanres = sscanf(ssp->Str, "%u", &val); |
| |
| if ( scanres == 1 ) |
| { |
| *value = val; |
| return FUNC_RETURN_OK; |
| } |
| |
| return UTIL_SIMPSTRING_WRONG_FORMAT; |
| } |
| |
| int GSimpStringToInt64(GSimpStringPtr ssp, int64_t *value) |
| { |
| Assert( ssp ); |
| Assert( value ); |
| |
| int64_t val; |
| int scanres = sscanf(ssp->Str, INT64_FORMAT, &val); |
| |
| if ( scanres == 1 ) |
| { |
| *value = val; |
| return FUNC_RETURN_OK; |
| } |
| |
| return UTIL_SIMPSTRING_WRONG_FORMAT; |
| } |
| |
| int GSimpStringToDouble(GSimpStringPtr ssp, double *value) |
| { |
| Assert( ssp ); |
| Assert( value ); |
| |
| double val; |
| int scanres = sscanf(ssp->Str, "%lf", &val); |
| |
| if ( scanres == 1 ) |
| { |
| *value = val; |
| return FUNC_RETURN_OK; |
| } |
| |
| return UTIL_SIMPSTRING_WRONG_FORMAT; |
| } |
| |
| int GSimpStringStartWith(GSimpStringPtr ssp, char *prefix) |
| { |
| Assert( ssp ); |
| Assert( prefix ); |
| |
| int prefixlen = strlen(prefix); |
| |
| if ( strncmp(ssp->Str, prefix, prefixlen) == 0 ) |
| { |
| return FUNC_RETURN_OK; |
| } |
| |
| return FUNC_RETURN_FAIL; |
| } |
| |
| int GSimpStringLocateChar(GSimpStringPtr ssp, char target, int *location) |
| { |
| Assert( ssp ); |
| Assert( location ); |
| |
| for ( int i = 0 ; i < ssp->Len ; ++i ) |
| { |
| if ( ssp->Str[i] == target ) |
| { |
| *location = i; |
| return FUNC_RETURN_OK; |
| } |
| } |
| |
| return FUNC_RETURN_FAIL; |
| } |
| |
| void GSimpStringReplaceChar(GSimpStringPtr ssp, char oldchar, char newchar) |
| { |
| Assert( ssp && ssp->Str ); |
| |
| for ( int i = 0 ; i < ssp->Len ; ++i ) |
| { |
| ssp->Str[i] = ssp->Str[i] == oldchar ? newchar : ssp->Str[i]; |
| } |
| } |
| |
| int GSimpStringReplaceFirst(GSimpStringPtr ssp, char *oldstr, char *newstr) |
| { |
| Assert( ssp ); |
| Assert( oldstr ); |
| Assert( newstr ); |
| |
| char *pos = strstr(ssp->Str, oldstr); |
| |
| /* If the old string does not exist, no need to do any update. */ |
| if ( pos == NULL ) |
| { |
| return FUNC_RETURN_OK; |
| } |
| |
| int nlen = ssp->Len + strlen(newstr) - strlen(oldstr); |
| char *buf = (char *)malloc(nlen+1); |
| |
| if ( buf == NULL ) |
| { |
| write_log("Function GSimpStringReplaceFirst out of memory"); |
| return UTIL_SIMPSTRING_OUT_OF_MEMORY; |
| } |
| |
| memset(buf, 0, sizeof(char)*(nlen+1)); |
| |
| int tlen1 = pos - ssp->Str; |
| if ( tlen1 > 0 ) |
| { |
| strncpy(buf, ssp->Str, tlen1); |
| buf[tlen1] = '\0'; |
| } |
| |
| strncpy(buf + tlen1, newstr, strlen(newstr)); |
| |
| int tlen2 = tlen1 + strlen(oldstr); |
| int tlen3 = tlen1 + strlen(newstr); |
| if ( tlen2 < ssp->Len ) |
| { |
| strncpy(buf + tlen3, |
| ssp->Str + tlen2, |
| ssp->Len - tlen2); |
| } |
| buf[nlen] = '\0'; |
| |
| setGSimpStringWithContent(ssp, buf, nlen); |
| |
| free(buf); |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| int GSimpStringSetOid(GSimpStringPtr ssp, Oid value) |
| { |
| Assert( ssp != NULL ); |
| |
| static char valuestr[64]; |
| int64_t val = value; |
| sprintf(valuestr, INT64_FORMAT, val); |
| setGSimpStringNoLen(ssp, valuestr); |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| int GSimpStringSetName(GSimpStringPtr ssp, Name value) |
| { |
| Assert( ssp != NULL ); |
| |
| setGSimpStringNoLen(ssp, value->data); |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| int GSimpStringSetBool(GSimpStringPtr ssp, bool value) |
| { |
| Assert( ssp != NULL ); |
| |
| setGSimpStringNoLen(ssp, value ? "true" : "false"); |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| int GSimpStringSetInt8(GSimpStringPtr ssp, int8_t value) |
| { |
| Assert( ssp != NULL ); |
| |
| static char valuestr[8]; |
| sprintf(valuestr, "%d", value); |
| setGSimpStringNoLen(ssp, valuestr); |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| int GSimpStringSetInt32(GSimpStringPtr ssp, int32_t value) |
| { |
| Assert( ssp != NULL ); |
| |
| static char valuestr[8]; |
| sprintf(valuestr, "%d", value); |
| setGSimpStringNoLen(ssp, valuestr); |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| int GSimpStringSetFloat(GSimpStringPtr ssp, float value) |
| { |
| Assert( ssp != NULL ); |
| |
| static char valuestr[32]; |
| sprintf(valuestr, "%f", value); |
| setGSimpStringNoLen(ssp, valuestr); |
| |
| return FUNC_RETURN_OK; |
| } |
| |
| /** |
| * Not supported in generic SimpString |
| int GSimpStringSetText(GSimpStringPtr ssp, text *value) |
| { |
| Assert(ssp != NULL); |
| |
| if ( value != NULL ) |
| { |
| char *tmpvalue = NULL; |
| |
| tmpvalue = DatumGetCString(DirectFunctionCall1(textout, |
| PointerGetDatum(value))); |
| setGSimpStringNoLen(ssp, tmpvalue); |
| free(tmpvalue); |
| } |
| else |
| { |
| setGSimpStringNoLen(ssp, ""); |
| } |
| |
| return FUNC_RETURN_OK; |
| } |
| * |
| */ |
| |
| int GSimpStringToOid(GSimpStringPtr ssp, Oid *value) |
| { |
| Assert( ssp ); |
| Assert( value ); |
| |
| int res = sscanf(ssp->Str, "%d", value); |
| |
| return res == 1 ? FUNC_RETURN_OK : UTIL_SIMPSTRING_WRONG_FORMAT; |
| } |
| |
| int GSimpStringTokens(GSimpStringPtr ssp, |
| char split, |
| GSimpStringPtr *tokens, |
| int *tokensize) |
| { |
| Assert( ssp ); |
| Assert( tokens ); |
| Assert( tokensize ); |
| |
| if ( ssp->Str == NULL || ssp->Len == 0 ) |
| { |
| *tokens = NULL; |
| *tokensize = 0; |
| return FUNC_RETURN_OK; |
| } |
| |
| *tokensize = 1; |
| for( int i = 0 ; i < ssp->Len ; ++i ) |
| { |
| if ( ssp->Str[i] == split ) |
| { |
| (*tokensize)++; |
| } |
| } |
| |
| *tokens = malloc(sizeof(GSimpString) * (*tokensize)); |
| if ( *tokens == NULL ) |
| { |
| write_log("Function GSimpStringTokens out of memory"); |
| return UTIL_SIMPSTRING_OUT_OF_MEMORY; |
| } |
| |
| char *prevp = ssp->Str; |
| char *p = ssp->Str; |
| for ( int i = 0 ; i < *tokensize ; ++i ) |
| { |
| while( *p != split && *p != '\0' ) |
| { |
| p++; |
| } |
| |
| initGSimpString(&((*tokens)[i])); |
| setGSimpStringWithContent(&((*tokens)[i]), prevp, p-prevp); |
| p++; |
| prevp = p; |
| } |
| |
| return FUNC_RETURN_OK; |
| } |