Go to the source code of this file.
Enumerations | |
enum | SqlStrAlterCaseAction { AlterCaseUpper, AlterCaseLower } |
Template argument for SqlStrAlterCase. More... | |
Functions | |
int FENNEL_CALCULATOR_EXPORT | SqlStrCat (char *dest, int destStorageBytes, int destLenBytes, char const *const str, int strLenBytes) |
Strcat. | |
int FENNEL_CALCULATOR_EXPORT | SqlStrCat (char *dest, int destStorageBytes, char const *const str1, int str1LenBytes, char const *const str2, int str2LenBytes) |
StrCat. | |
int FENNEL_CALCULATOR_EXPORT | SqlStrCmp_Bin (char const *const str1, int str1LenBytes, char const *const str2, int str2LenBytes) |
StrCmp. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int | SqlStrCmp (char const *const str1, int str1LenBytes, char const *const str2, int str2LenBytes, int trimchar= ' ') |
StrCmp. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int | SqlStrCpy_Fix (char *dest, int destStorageBytes, char const *const str, int strLenBytes, int padchar= ' ') |
StrCpy. | |
int FENNEL_CALCULATOR_EXPORT | SqlStrCpy_Var (char *dest, int destStorageBytes, char const *const str, int strLenBytes) |
StrCpy. | |
int FENNEL_CALCULATOR_EXPORT | SqlStrLenBit (int strLenBytes) |
StrLen in bits. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int | SqlStrLenChar (char const *const str, int strLenBytes) |
StrLen in characters. | |
int FENNEL_CALCULATOR_EXPORT | SqlStrLenOct (int strLenBytes) |
StrLen in octets. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int | SqlStrOverlay (char *dest, int destStorageBytes, char const *const str, int strLenBytes, char const *const over, int overLenBytes, int startChar, int lenChar, int lenSpecified) |
Overlay. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int | SqlStrPos (char const *const str, int strLenBytes, char const *const find, int findLenBytes) |
Position. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int | SqlStrSubStr (char const **dest, int destStorageBytes, char const *const str, int strLenBytes, int subStartChar, int subLenChar, int subLenCharSpecified) |
Substring by reference. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint, SqlStrAlterCaseAction Action> | |
int | SqlStrAlterCase (char *dest, int destStorageBytes, char const *const src, int srcLenBytes, char const *const locale=0) |
toLower and toUpper. CHAR/VARCHAR. Returns new length. ASCII & UCS2. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int | SqlStrTrim (char *dest, int destStorageBytes, char const *const str, int strLenBytes, int trimLeft, int trimRight, int trimchar= ' ') |
Trim padding. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int | SqlStrTrim (char const **result, char const *const str, int strLenBytes, int trimLeft, int trimRight, int trimchar= ' ') |
Trim padding by reference. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int64_t | SqlStrCastToExact (char const *const str, int strLenBytes, int padChar= ' ') |
SqlStrCastToExact. | |
int64_t | SqlExactMax (int precision, bool negative) |
SqlExactMax. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int64_t | SqlStrCastToExact (char const *const str, int strLenBytes, int precision, int scale, int padChar= ' ') |
SqlStrCastToExact. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
double | SqlStrCastToApprox (char const *const str, int strLenBytes, int padChar= ' ') |
SqlStrCastToApprox. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int | SqlStrCastFromExact (char *dest, int destStorageBytes, int64_t src, bool fixed, int padchar= ' ') |
SqlStrCastFromExact. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int | SqlStrCastFromExact (char *dest, int destStorageBytes, int64_t src, int precision, int scale, bool fixed, int padchar= ' ') |
SqlStrCastFromExact. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int | SqlStrCastFromApprox (char *dest, int destStorageBytes, double src, bool isFloat, bool fixed, int padchar= ' ') |
SqlStrCastFromApprox. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int | SqlStrCastToVarChar (char *dest, int destStorageBytes, char *src, int srcLenBytes, int *rightTruncWarning=NULL, int padchar= ' ') |
SqlStrCastToVarChar. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int | SqlStrCastToChar (char *dest, int destStorageBytes, char *src, int srcLenBytes, int *rightTruncWarning=NULL, int padchar= ' ') |
SqlStrCastToChar. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
bool | SqlStrCastToBoolean (char const *const str, int strLenBytes, int padChar= ' ') |
SqlStrCastToBoolean. | |
template<int CodeUnitBytes, int MaxCodeUnitsPerCodePoint> | |
int | SqlStrCastFromBoolean (char *dest, int destStorageBytes, bool src, bool fixed, int padchar= ' ') |
SqlStrCastFromBoolean Char & VarChar. |
These functions are called by ExtendedInstructions in ExtString.h
This library supports 8-bit characters, labeled somewhat misleadingly as Ascii, and fixed width 2-byte UCS2 characters. No assumptions are made about alignment of ASCII strings. UCS2 strings are assumed to be aligned, in order to work efficently with the ICU library. Currently there are non-ICU UCS2 routines that make no assumptions about alignment that could probably be made faster.
Some functions work for either Ascii or UCS2 encodings. Other functions are templated in order to work for either type. The templating system as defined may be sufficent to also support UTF-8, UTF-16 and UTF-32 encodings.
The template is:
template <int CodeUnitBytes, int MaxCodeUnitsPerCodePoint>.
A code unit is the atomic unit that represents part or all of a code point. A code point represents a character. The character encoding form (e.g. ASCII, UCS2, UTF8) determines how each code point is represented by one or more code units.
Currently this templating form does not take endian issues into account, but this information may be encoded in the strings, and may not have to be explicit.
Definition in file SqlString.h.
Template argument for SqlStrAlterCase.
Definition at line 590 of file SqlString.h.
00590 { 00591 AlterCaseUpper, 00592 AlterCaseLower 00593 };
int64_t SqlExactMax | ( | int | precision, | |
bool | negative | |||
) | [inline] |
SqlExactMax.
Returns the maximum integer with the given precision
Definition at line 1008 of file SqlString.h.
Referenced by SqlStrCastToExact().
01009 { 01010 int64_t rv; 01011 if (precision < 19) { 01012 rv = 1; 01013 for (int i = 0; i < precision; i++) { 01014 rv *= 10; 01015 } 01016 rv--; 01017 } else { 01018 if (negative) { 01019 rv = -std::numeric_limits<int64_t>::min(); 01020 } else { 01021 rv = std::numeric_limits<int64_t>::max(); 01022 } 01023 } 01024 return rv; 01025 }
int SqlStrAlterCase | ( | char * | dest, | |
int | destStorageBytes, | |||
char const *const | src, | |||
int | srcLenBytes, | |||
char const *const | locale = 0 | |||
) |
toLower and toUpper. CHAR/VARCHAR. Returns new length. ASCII & UCS2.
Definition at line 600 of file SqlString.h.
References AlterCaseLower, and AlterCaseUpper.
00606 { 00607 int retVal; 00608 00609 if (srcLenBytes > destStorageBytes) { 00610 // SQL99 22.1 22-001 "String Data Right truncation" 00611 throw "22001"; 00612 } 00613 00614 if (MaxCodeUnitsPerCodePoint == 1) { 00615 if (CodeUnitBytes == 1) { 00616 register char const * s = src; 00617 register char* d = dest; 00618 char* e = dest + srcLenBytes; 00619 while (d < e) { 00620 switch (Action) { 00621 case AlterCaseUpper: 00622 *(d++) = toupper(*(s++)); 00623 break; 00624 case AlterCaseLower: 00625 *(d++) = tolower(*(s++)); 00626 break; 00627 default: 00628 throw std::logic_error("AlterCase Action"); 00629 break; 00630 } 00631 } 00632 retVal = srcLenBytes; 00633 } else if (CodeUnitBytes == 2) { 00634 // UCS2 00635 #ifdef HAVE_ICU 00636 assert(!(destStorageBytes & srcLenBytes & 1)); 00637 // strings must be short aligned 00638 // TODO: Change tuples to force strings to be short aligned. 00639 assert(!(reinterpret_cast<int>(src) & 1)); 00640 assert(!(reinterpret_cast<int>(dest) & 1)); 00641 assert(sizeof(UChar) == 2); 00642 assert(locale); // Don't allow locale defaulting 00643 00644 int32_t destStorageUChar = destStorageBytes >> 1; 00645 int32_t srcLenUChar = srcLenBytes >> 1; 00646 int32_t newLenUChar; 00647 UErrorCode errorCode = U_ZERO_ERROR; 00648 00649 switch (Action) { 00650 case AlterCaseUpper: 00651 newLenUChar = u_strToUpper( 00652 reinterpret_cast<UChar*>(dest), 00653 destStorageUChar, 00654 reinterpret_cast<UChar const *>(src), 00655 srcLenUChar, 00656 locale, 00657 &errorCode); 00658 break; 00659 case AlterCaseLower: 00660 newLenUChar = u_strToLower( 00661 reinterpret_cast<UChar*>(dest), 00662 destStorageUChar, 00663 reinterpret_cast<UChar const *>(src), 00664 srcLenUChar, 00665 locale, 00666 &errorCode); 00667 break; 00668 default: 00669 throw std::logic_error("AlterCase Action"); 00670 break; 00671 } 00672 00673 if (newLenUChar > destStorageUChar) { 00674 // SQL99 22.1 22-001 "String Data Right truncation" 00675 throw "22001"; 00676 } 00677 if (U_FAILURE(errorCode)) { 00678 // TODO: Clean up ICU error handling. 00679 // Other ICU error. Unlikely to occur? 00680 throw u_errorName(errorCode); 00681 } 00682 retVal = newLenUChar << 1; 00683 #else 00684 throw std::logic_error("no UCS2"); 00685 #endif 00686 } else { 00687 throw std::logic_error("no such encoding"); 00688 } 00689 } else { 00690 // Note: Potentially UTF16 can be handled by UCS2 code 00691 throw std::logic_error("no UTF8/16/32"); 00692 } 00693 return retVal; 00694 }
int SqlStrCastFromApprox | ( | char * | dest, | |
int | destStorageBytes, | |||
double | src, | |||
bool | isFloat, | |||
bool | fixed, | |||
int | padchar = ' ' | |||
) |
SqlStrCastFromApprox.
Char & VarChar. Ascii only.
Cast an approximate (e.g. floating point) numeric to a string.
This routine is not fully SQL99 compliant. Deltas are in 6.22 General Rule 8 b i 2 and 9 b i 2. Currently the minimal string is not produced. Instead, the maximum precision (roughly 16 digits) is always produced. Trade brevity for precision for now as compliance is not trivial with printf.
Pad character code points that require more than one code unit are currently unsupported.
See SQL99 Part 2 Section 5.3 Format <approximate numeric literal> for details on the format of an approximate numeric. Basically nnn.mmmExxx.
See SqlStringCastFromExact for an alternative implementation that could be better/cheaper/faster.
E gives [-]d.dddE[+,-]dd format %.16 gives, roughly, maximum precision for a double on a x86. This should be parameterized. TODO: Parameterize precision and format of conversion.
Definition at line 1672 of file SqlString.h.
References max().
01679 { 01680 int rv; 01681 01682 if (MaxCodeUnitsPerCodePoint == 1) { 01683 if (CodeUnitBytes == 1) { 01684 // ASCII 01685 if (src == 0.0) { 01686 // 6.22 General Rule 8, case b i 2 and 01687 // 6.22 General Rule 9, case b i 2 01688 if (destStorageBytes >= 3) { 01689 memcpy(dest, "0E0", 3); 01690 rv = 3; 01691 } else { 01692 // SQL99 Part 2 Section 6.22 General Rule 8.b.iii.4 (fixed 01693 // length) "22001" data exception - string 01694 01695 // SQL99 Part 2 Section 6.22 General Rule 9.b.iii.3 01696 // (variable length) "22001" data exception -- string data, 01697 // right truncation 01698 throw "22001"; 01699 } 01700 } else { 01701 // Note: can't always snprintf directly into dest, due to 01702 // null termination wasting a byte. 01703 01708 01709 int max_precision = (isFloat) ? 7 : 16; 01710 char buf[36]; // #.16E should always fit in 22 bytes. 01711 rv = snprintf(buf, 35, "%.*E", max_precision, src); 01712 01713 // snprintf does not include null termination in length 01714 assert(rv >= 0 && rv <= 35); 01715 01716 if (src > std::numeric_limits<double>::max()) { 01717 strcpy(buf, "INF"); 01718 rv = 3; 01719 } else if (src < -std::numeric_limits<double>::max()) { 01720 strcpy(buf, "-INF"); 01721 rv = 4; 01722 } 01723 01724 // Trim trailing zeros from mantissa, and initial zeros 01725 // from exponent 01726 int buflen = rv; 01727 int last_nonzero = (src < 0) ? 1 : 0; 01728 int eindex = last_nonzero + max_precision + 2; 01729 int eneg = 0; 01730 int explen = 1; 01731 01732 if ((buflen > eindex) && buf[eindex] == 'E') { 01733 // Normal number with exponent 01734 01735 // Round up if needed 01736 if ((buf[eindex - 1] >= '5') && (buf[eindex - 1] <= '9')) { 01737 buf[eindex - 1] = '0'; 01738 for (int i = eindex - 2; i >= last_nonzero; i--) { 01739 if (buf[i] == '9') { 01740 buf[i] = '0'; 01741 } else if (buf[i] != '.') { 01742 buf[i]++; 01743 break; 01744 } 01745 } 01746 01747 // See if initial digit overflowed (very unlikely) 01748 if (buf[last_nonzero] == '0') { 01749 buf[last_nonzero] = '1'; 01750 for (int i = eindex - 1; 01751 i > last_nonzero + 2; 01752 i--) 01753 { 01754 buf[i] = buf[i - 1]; 01755 } 01756 buf[last_nonzero + 2] = '0'; 01757 01758 // increment exponent 01759 int exp; 01760 sscanf(buf + eindex + 1, "%d", &exp); 01761 sprintf(buf + eindex + 1, "%d", exp + 1); 01762 buflen = strlen(buf); 01763 } 01764 } 01765 01766 // Ignore last digit 01767 // only need 16 digits in total, 15 digits after '.' 01768 for (int i = eindex - 2; i >= 0; i--) { 01769 if ((buf[i] >= '1') && (buf[i] <= '9')) { 01770 last_nonzero = i; 01771 break; 01772 } 01773 } 01774 eneg = (buf[eindex + 1] == '-') ? 1 : 0; 01775 for (int i = eindex + 1; i < buflen; i++) { 01776 if ((buf[i] >= '1') && (buf[i] <= '9')) { 01777 explen = buflen - i; 01778 break; 01779 } 01780 } 01781 01782 // final length = mantissa + 'E' + optional '-' + explen 01783 rv = last_nonzero + 1 + 1 + eneg + explen; 01784 } else { 01785 // Special number (INF, -INF, NaN) 01786 rv = buflen; 01787 } 01788 01789 if (rv <= destStorageBytes) { 01790 if (rv == buflen) { 01791 // Copy all 01792 memcpy(dest, buf, rv); 01793 } else { 01794 // Don't copy trailing zeros of mantissa 01795 memcpy(dest, buf, last_nonzero + 1); 01796 rv = last_nonzero + 1; 01797 dest[rv++] = 'E'; 01798 if (eneg) { 01799 dest[rv++] = '-'; 01800 } 01801 // Copy exponent 01802 memcpy(dest + rv, buf + (buflen - explen), explen); 01803 rv += explen; 01804 } 01805 } else { 01806 // SQL99 Part 2 Section 6.22 General Rule 8.b.iii.4 (fixed 01807 // length) "22001" data exception - string 01808 01809 // SQL99 Part 2 Section 6.22 General Rule 9.b.iii.3 01810 // (variable length) "22001" data exception -- string data, 01811 // right truncation 01812 throw "22001"; 01813 } 01814 } 01815 01816 if (fixed) { 01817 memset(dest + rv, padchar, destStorageBytes - rv); 01818 rv = destStorageBytes; 01819 } 01820 01821 } else if (CodeUnitBytes == 2) { 01822 // TODO: Add UCS2 here 01823 throw std::logic_error("no UCS2"); 01824 } else { 01825 throw std::logic_error("no such encoding"); 01826 } 01827 } else { 01828 throw std::logic_error("no UTF8/16/32"); 01829 } 01830 01831 return rv; 01832 }
int SqlStrCastFromBoolean | ( | char * | dest, | |
int | destStorageBytes, | |||
bool | src, | |||
bool | fixed, | |||
int | padchar = ' ' | |||
) |
SqlStrCastFromBoolean Char & VarChar.
Ascii only.
Cast a boolea to a string.
SQL2003 Part 2 Section 6.12 General Rules 10.e and 11.e specifies that false should be cast to 'false' and true to 'true'.
Definition at line 2037 of file SqlString.h.
02043 { 02044 int rv; 02045 02046 if (MaxCodeUnitsPerCodePoint == 1) { 02047 if (CodeUnitBytes == 1) { 02048 // ASCII 02049 02050 // SQL2003 6.12 General Rule 10, case e i,ii and 02051 // SQL2003 6.12 General Rule 11, case e i,ii 02052 if (src && destStorageBytes >= 4) { 02053 memcpy(dest, "TRUE", 4); 02054 rv = 4; 02055 } else if (!src && destStorageBytes >= 5) { 02056 memcpy(dest, "FALSE", 5); 02057 rv = 5; 02058 } else { 02059 // SQL2003 Part 2 Section 6.12 General Rule 02060 // 10.e.iii (fixed length) and 11.e.iii (variable length) 02061 // "22018" data exception -- invalid character value for cast 02062 throw "22018"; 02063 } 02064 02065 if (fixed) { 02066 memset(dest + rv, padchar, destStorageBytes - rv); 02067 rv = destStorageBytes; 02068 } 02069 02070 } else if (CodeUnitBytes == 2) { 02071 // TODO: Add UCS2 here 02072 throw std::logic_error("no UCS2"); 02073 } else { 02074 throw std::logic_error("no such encoding"); 02075 } 02076 } else { 02077 throw std::logic_error("no UTF8/16/32"); 02078 } 02079 02080 return rv; 02081 }
int SqlStrCastFromExact | ( | char * | dest, | |
int | destStorageBytes, | |||
int64_t | src, | |||
int | precision, | |||
int | scale, | |||
bool | fixed, | |||
int | padchar = ' ' | |||
) |
SqlStrCastFromExact.
Char & VarChar. Ascii only.
Cast an exact numeric with precision and scale to a string.
This routine may not be compliant with the SQL99 standard.
Pad character code points that require more than one code unit are currently unsupported.
Definition at line 1525 of file SqlString.h.
References SqlStrCastFromExact().
01533 { 01534 int rv; 01535 01536 if (MaxCodeUnitsPerCodePoint == 1) { 01537 if (CodeUnitBytes == 1) { 01538 // ASCII 01539 01540 // TODO: Check performance of current implementation against 01541 // TODO: a version with % and /10, etc. 01542 01543 if (scale == 0) { 01544 // Scale is 0, same as normal cast 01545 rv = SqlStrCastFromExact 01546 <CodeUnitBytes, MaxCodeUnitsPerCodePoint> 01547 (dest, destStorageBytes, src, fixed, padchar); 01548 } else if (scale > 0) { 01549 // Positive Scale 01550 int ndigits, decimal, sign = 0; 01551 char buf[36]; // #%lld should always fit in 21 bytes. 01552 rv = snprintf(buf, 35, "%" FMT_INT64, abs(src)); 01553 // snprintf does not return null termination in length 01554 assert(rv >= 0 && rv <= 35); 01555 01556 ndigits = rv; 01557 if (src < 0) { 01558 sign = 1; 01559 rv++; 01560 } 01561 01562 // Figure out where to add decimal point 01563 decimal = ndigits - scale; 01564 if (decimal < 0) { 01565 // Need to pad with 0s 01566 rv += (-decimal) + 1; 01567 } else { 01568 rv += 1; 01569 } 01570 01571 // Check if there is enough space 01572 if (rv > destStorageBytes) { 01573 // SQL99 Part 2 Section 6.22 General Rule 8.a.iv (fixed 01574 // length) "22001" data exception -- string data, right 01575 // truncation 01576 01577 // SQL99 Part 2 Section 6.22 General Rule 9.a.iii (variable 01578 // length) "22001" data exception -- string data, right 01579 // truncation 01580 throw "22001"; 01581 } 01582 01583 // Copy into destination buffer, placing the '.' appropriately 01584 if (sign) { 01585 dest[0] = '-'; 01586 } 01587 01588 if (decimal < 0) { 01589 int pad = -decimal; 01590 dest[sign] = '.'; 01591 memset(dest + sign + 1, '0', pad); 01592 memcpy(dest + sign + 1 + pad, buf, ndigits); 01593 } else { 01594 memcpy(dest + sign, buf, decimal); 01595 dest[decimal + sign] = '.'; 01596 memcpy(dest + sign + 1 + decimal, buf + decimal, scale); 01597 } 01598 01599 if (fixed) { 01600 memset(dest + rv, padchar, destStorageBytes - rv); 01601 rv = destStorageBytes; 01602 } 01603 01604 } else { 01605 // Negative Scale 01606 int nzeros = (src != 0) ? -scale : 0; 01607 int len; 01608 char buf[36]; // #%lld should always fit in 21 bytes. 01609 rv = snprintf(buf, 35, "%" FMT_INT64, src); 01610 // snprintf does not return null termination in length 01611 assert(rv >= 0 && rv <= 35); 01612 01613 len = rv; 01614 01615 // Check if there is enough space 01616 rv += nzeros; 01617 if (rv > destStorageBytes) { 01618 // SQL99 Part 2 Section 6.22 General Rule 8.a.iv (fixed 01619 // length) "22001" data exception -- string data, right 01620 // truncation 01621 01622 // SQL99 Part 2 Section 6.22 General Rule 9.a.iii (variable 01623 // length) "22001" data exception -- string data, right 01624 // truncation 01625 throw "22001"; 01626 } 01627 01628 // Add zeros 01629 memcpy(dest, buf, len); 01630 memset(dest + len, '0', nzeros); 01631 01632 if (fixed) { 01633 memset(dest + rv, padchar, destStorageBytes - rv); 01634 rv = destStorageBytes; 01635 } 01636 } 01637 } else if (CodeUnitBytes == 2) { 01638 // TODO: Add UCS2 here 01639 throw std::logic_error("no UCS2"); 01640 } else { 01641 throw std::logic_error("no such encoding"); 01642 } 01643 } else { 01644 throw std::logic_error("no UTF8/16/32"); 01645 } 01646 01647 return rv; 01648 }
int SqlStrCastFromExact | ( | char * | dest, | |
int | destStorageBytes, | |||
int64_t | src, | |||
bool | fixed, | |||
int | padchar = ' ' | |||
) |
SqlStrCastFromExact.
Char & VarChar. Ascii only.
Cast an exact numeric to a string.
This routine may not be compliant with the SQL99 standard.
Pad character code points that require more than one code unit are currently unsupported.
Definition at line 1370 of file SqlString.h.
Referenced by SqlStrCastFromExact().
01376 { 01377 int rv; 01378 01379 if (MaxCodeUnitsPerCodePoint == 1) { 01380 if (CodeUnitBytes == 1) { 01381 // ASCII 01382 01383 // TODO: Check performance of doing snprintf and a memcpy vs 01384 // TODO: a home-rolled version with % and /10, etc. Both 01385 // TOOD: require a copy, or some precomputation of string length. 01386 // TODO: Hard to say which would be faster w/o implementing both. 01387 // TODO: Note: can't always snprintf directly into dest, due to 01388 // TODO: null termination wasting a byte. 01389 01390 // A previous implementation (retained below) 01391 // optimistically tried to snprintf into the output 01392 // buffer, and retried if it would have fit, save for the 01393 // null termination. The logic gets complicated in the 01394 // face of snprintf implementatins that return -1, where 01395 // such information is not possible. Until an 01396 // optimization pass can be made, always snprintf into a 01397 // temporary buffer, and memcpy the result back if it 01398 // would fit. 01399 01400 char buf[36]; // #%lld should always fit in 21 bytes. 01401 01402 // TODO: Bug on mingw where int64_t is not handled correctly 01403 // by snprintf %lld 01404 // Windows (MS dll) uses %I64d but that causes warning 01405 // with gcc -Wall 01406 rv = snprintf(buf, 35, "%" FMT_INT64, src); 01407 01408 // snprintf does not return null termination in length 01409 assert(rv >= 0 && rv <= 35); 01410 if (rv <= destStorageBytes) { 01411 memcpy(dest, buf, rv); 01412 } else { 01413 memcpy(dest, buf, destStorageBytes); 01414 // SQL99 Part 2 Section 6.22 General Rule 8.a.iv (fixed 01415 // length), "22001" data exception -- string data, right 01416 // truncation 01417 01418 // SQL99 Part 2 Section 6.22 General Rule 9.a.iii (variable 01419 // length) "22001" data exception -- string data, right 01420 // truncation 01421 throw "22001"; 01422 } 01423 01424 01425 #ifdef SECOND_ALTERNATIVE_IMPLEMENTATION_DOES_NOT_WORK_ON_CYGWIN 01426 01427 // Older glibc returns -1 from snprintf. logic gets 01428 // complicated 01429 01430 rv = snprintf(dest, destStorageBytes, "%" FMT_INT64, src); 01431 if (rv == destStorageBytes) { 01432 // Would have fit, except for the null termination. Do 01433 // over into a temporary buf, copy results back. 01434 // Dreary performance in this case, which may be more common 01435 // than random chance would predict. If this is 01436 // not acceptable, see ALTERNATIVE_IMPLEMENTATION below 01437 01438 char buf[36]; // should always fit in 21 bytes. 01439 rv = snprintf(buf, 35, "%" FMT_INT64, src); 01440 assert(rv == destStorageBytes); 01441 memcpy(dest, buf, destStorageBytes); 01442 } else if (rv > destStorageBytes) { 01443 // SQL99 Part 2 Section 6.22 General Rule 8.a.iv (fixed 01444 // length), "22001" data exception -- string data, right 01445 // truncation 01446 01447 // SQL99 Part 2 Section 6.22 General Rule 9.a.iii (variable 01448 // length) "22001" data exception -- string data, right 01449 // truncation 01450 throw "22001"; 01451 } 01452 #endif 01453 01454 #ifdef ALTERNATIVE_IMPLEMENTATION_UNTESTED_UNPROFILED_AND_PERHAPS_UNHOLY 01455 // assume any int64_t will fit in 22 bytes: 01456 // int64_t has 19 digits, plus space for a - sign and null 01457 // termination is 21 bytes. Add one to round up to 22 bytes. 01458 01459 // if storage >= 22 bytes, snprintf directly into dest 01460 // as a first-order optimization. 01461 if (destStorageBytes >= 22) { 01462 rv = snprintf(dest, destStorageBytes, "%" FMT_INT64, src); 01463 assert(rv <= destStorageBytes); // impossible? 01464 if (rv > destStorageBytes) { 01465 // Just in case 22 byte assumption isn't valid 01466 01467 // SQL99 Part 2 Section 6.22 General Rule 8.a.iv (fixed 01468 // length) "22001" data exception -- string data, right 01469 // truncation 01470 01471 // SQL99 Part 2 Section 6.22 General Rule 9.a.iii (variable 01472 // length), "22001" data exception -- string data, right 01473 // truncation 01474 throw "22001"; 01475 } 01476 } else { 01477 // If src is somewhat less than max or min, it might 01478 // be short enough to fit into destStorageBytes anyway. 01479 // Write to buf to get around annoying null termination 01480 // issue wasting one byte. 01481 01482 char buf[24]; 01483 rv = snprintf(buf, destStorageBytes, "%" FMT_INT64, src); 01484 if (rv > destStorageBytes) { 01485 // SQL99 Part 2 Section 6.22 General Rule 8.a.iv (fixed 01486 // length) "22001" data exception -- string data, right 01487 // truncation 01488 01489 // SQL99 Part 2 Section 6.22 General Rule 9.a.iii (variable 01490 // length) "22001" data exception -- string data, right 01491 // truncation 01492 throw "22001"; 01493 } 01494 memcpy(dest, buf, rv); 01495 } 01496 #endif 01497 if (fixed) { 01498 memset(dest + rv, padchar, destStorageBytes - rv); 01499 rv = destStorageBytes; 01500 } 01501 01502 } else if (CodeUnitBytes == 2) { 01503 // TODO: Add UCS2 here 01504 throw std::logic_error("no UCS2"); 01505 } else { 01506 throw std::logic_error("no such encoding"); 01507 } 01508 } else { 01509 throw std::logic_error("no UTF8/16/32"); 01510 } 01511 01512 return rv; 01513 }
double SqlStrCastToApprox | ( | char const *const | str, | |
int | strLenBytes, | |||
int | padChar = ' ' | |||
) |
SqlStrCastToApprox.
Char & VarChar. Ascii only.
Cast a string to an approximate (e.g. floating point) numeric.
See SQL99 Part 2 Section 5.3 Format <approximate numeric literal> for details on the format of an approximate numeric. Basically nnn.mmm[Exxx].
Definition at line 1294 of file SqlString.h.
References max().
01298 { 01299 double rv; 01300 if (MaxCodeUnitsPerCodePoint == 1) { 01301 if (CodeUnitBytes == 1) { 01302 // ASCII 01303 01304 char const *ptr = str; 01305 char const *end = str + strLenBytes; 01306 char *endptr; 01307 01308 // Skip past any leading whitespace. Allows string with 01309 // arbitrary amounts of leading whitespace. 01310 while (ptr < end && *ptr == padChar) { 01311 ptr++; 01312 } 01313 int max = end - ptr; 01314 #ifdef __MSVC__ 01315 char *tmp = (char *) _alloca(max + 1); 01316 #else 01317 char tmp[max + 1]; 01318 #endif 01319 memcpy(tmp, ptr, max); 01320 tmp[max] = 0; 01321 rv = strtod(tmp, &endptr); 01322 01323 if (endptr == tmp) { 01324 // SQL99 Part 2 Section 6.22 General Rule 7.b.i "22018" 01325 // data exception -- invalid character value for cast 01326 throw "22018"; 01327 } 01328 01329 // verify that trailing characters are all padChar 01330 ptr += endptr - tmp; // advance past parsed digits 01331 while (ptr < end) { 01332 if (*ptr != padChar) { 01333 // SQL99 Part 2 Section 6.22 General Rule 7.b.i "22018" 01334 // data exception -- invalid character value for cast 01335 throw "22018"; 01336 } 01337 ptr++; 01338 } 01339 01340 // Throw exception if overflow 01341 double dmax = std::numeric_limits<double>::max(); 01342 if (rv > dmax || rv < -dmax) { 01343 // Overflow 01344 throw "22003"; 01345 } 01346 01347 } else if (CodeUnitBytes == 2) { 01348 // TODO: Add UCS2 here 01349 throw std::logic_error("no UCS2"); 01350 } else { 01351 throw std::logic_error("no such encoding"); 01352 } 01353 } else { 01354 throw std::logic_error("no UTF8/16/32"); 01355 } 01356 01357 return rv; 01358 }
bool SqlStrCastToBoolean | ( | char const *const | str, | |
int | strLenBytes, | |||
int | padChar = ' ' | |||
) |
SqlStrCastToBoolean.
Char & VarChar. Ascii only.
Cast a string to an boolean
See SQL2003 Part 2 Section 5.3 Format <boolean literal> and General Rules 10 for details on the format of a boolean. Boolean can be true, false, or unknown (null). This method only casts from 'true' and 'false'.
Definition at line 1978 of file SqlString.h.
01982 { 01983 bool rv; 01984 if (MaxCodeUnitsPerCodePoint == 1) { 01985 if (CodeUnitBytes == 1) { 01986 // ASCII 01987 char const *ptr = str; 01988 char const *end = str + strLenBytes; 01989 01990 // Skip past any leading whitespace. 01991 while (ptr < end && *ptr == padChar) { 01992 ptr++; 01993 } 01994 // Check if true, false, or unknown 01995 if ((end - ptr) >= 4 && strncasecmp(ptr, "TRUE", 4) == 0) { 01996 rv = true; 01997 ptr += 4; // advance past true 01998 } else if ((end - ptr) >= 5 && strncasecmp(ptr, "FALSE", 5) == 0) { 01999 rv = false; 02000 ptr += 5; // advance past false; 02001 } else { 02002 // SQL2003 Part 2 Section 6.12 General Rule 20.a.ii "22018" 02003 // data exception -- invalid character value for cast 02004 throw "22018"; 02005 } 02006 02007 // verify that trailing characters are all padChar 02008 while (ptr < end) { 02009 if (*ptr != padChar) { 02010 // SQL2003 Part 2 Section 6.12 General Rule 20.a.ii "22018" 02011 // data exception -- invalid character value for cast 02012 throw "22018"; 02013 } 02014 ptr++; 02015 } 02016 } else if (CodeUnitBytes == 2) { 02017 // TODO: Add UCS2 here 02018 throw std::logic_error("no UCS2"); 02019 } else { 02020 throw std::logic_error("no such encoding"); 02021 } 02022 } else { 02023 throw std::logic_error("no UTF8/16/32"); 02024 } 02025 02026 return rv; 02027 }
int SqlStrCastToChar | ( | char * | dest, | |
int | destStorageBytes, | |||
char * | src, | |||
int | srcLenBytes, | |||
int * | rightTruncWarning = NULL , |
|||
int | padchar = ' ' | |||
) |
SqlStrCastToChar.
Ascii only.
Pad character code points that require more than one code unit are currently unsupported. Assumes that non-NULL rightTruncWarning points to an int initialized to zero (0).
See SQL99 Part 2 Section 6.22 General Rule 9.c for rules on this cast.
Definition at line 1911 of file SqlString.h.
01918 { 01919 int rv; 01920 01921 if (MaxCodeUnitsPerCodePoint == 1) { 01922 if (CodeUnitBytes == 1) { 01923 // ASCII 01924 if (srcLenBytes <= destStorageBytes) { 01925 memcpy(dest, src, srcLenBytes); 01926 rv = srcLenBytes; 01927 01928 if (srcLenBytes < destStorageBytes) { 01929 memset( 01930 dest + srcLenBytes, 01931 padchar, 01932 destStorageBytes - srcLenBytes); 01933 rv = destStorageBytes; 01934 } 01935 } else { 01936 memcpy(dest, src, destStorageBytes); 01937 rv = destStorageBytes; 01938 01939 for (char *trunc = src + destStorageBytes, 01940 *end = src + srcLenBytes; 01941 trunc != end; 01942 trunc++) 01943 { 01944 if (*trunc != padchar) { 01945 // Spec says this is just a warning (see SQL99 Part 2 01946 // Section 6.22 General Rule 9.c.ii). Let the caller 01947 // handle it. 01948 if (rightTruncWarning != NULL) { 01949 *rightTruncWarning = 1; 01950 } 01951 } 01952 } 01953 } 01954 } else if (CodeUnitBytes == 2) { 01955 // TODO: Add UCS2 here 01956 throw std::logic_error("no UCS2"); 01957 } else { 01958 throw std::logic_error("no such encoding"); 01959 } 01960 } else { 01961 throw std::logic_error("no UTF8/16/32"); 01962 } 01963 01964 return rv; 01965 }
int64_t SqlStrCastToExact | ( | char const *const | str, | |
int | strLenBytes, | |||
int | precision, | |||
int | scale, | |||
int | padChar = ' ' | |||
) |
SqlStrCastToExact.
Char & VarChar. Ascii only.
Cast a string to an exact numeric with precision and scale.
Definition at line 1032 of file SqlString.h.
References min(), SqlExactMax(), and SqlStrCastToExact().
01038 { 01039 int64_t rv = 0; 01040 bool negative = false; 01041 01042 assert(precision > 0); 01043 if (MaxCodeUnitsPerCodePoint == 1) { 01044 if (CodeUnitBytes == 1) { 01045 // ASCII 01046 // comparison must be unsigned to work for > 128 01047 unsigned char const *ptr = 01048 reinterpret_cast<unsigned char const *>(str); 01049 unsigned char const *end = 01050 reinterpret_cast<unsigned char const *>(str + strLenBytes); 01051 01052 // STATE: parse optional sign, consume leading white space 01053 while (ptr < end) { 01054 if (*ptr == '-') { 01055 // move onto next state, do not allow whitespace 01056 // after -, for example '- 4' is not allowed 01057 negative = true; 01058 ptr++; 01059 break; 01060 } else if (*ptr == '+') { 01061 // move onto next state, do not allow whitespace 01062 // after +, for example '+ 4' is not allowed 01063 ptr++; 01064 break; 01065 } else if (*ptr == padChar) { 01066 // consume leading whitespace 01067 ptr++; 01068 } else if (*ptr >= '0' && *ptr <= '9') { 01069 // found a number. don't advance, move onto next state 01070 break; 01071 } else if (*ptr == '.') { 01072 // found decimal point. don't advance, move onto next state 01073 break; 01074 } else { 01075 // unexpected character found 01076 // SQL99 Part 2 Section 6.22 General Rule 6.b.i data 01077 // exception -- invalid character value for cast 01078 throw "22018"; 01079 } 01080 } 01081 01082 if (ptr >= end) { 01083 // no number found 01084 // SQL99 Part 2 Section 6.22 General Rule 6.b.i data 01085 // exception -- invalid character value for cast 01086 throw "22018"; 01087 } 01088 01089 // STATE: Parse numbers until padChar, end, or illegal char 01090 bool parsed = false; 01091 bool decimal_parsed = false; 01092 bool roundup = false; 01093 bool overflow = false; 01094 int ignored = 0; 01095 int decimal_position = 0; 01096 int mantissa_digits = 0, parsed_digits = 0; 01097 int digit; 01098 int64_t mantissa = 0; 01099 int64_t exponent = 0; 01100 while (ptr < end) { 01101 if (*ptr >= '0' && *ptr <= '9') { 01102 // number 01103 digit = (*(ptr++) - '0'); 01104 01105 // Only add to mantissa if precision not reached 01106 if (mantissa_digits < precision) { 01107 if (mantissa_digits < 18) { 01108 mantissa = mantissa * 10 + digit; 01109 } else if (mantissa_digits == 18) { 01110 // Handle 19th digit overflow 01111 int64_t tmp; 01112 tmp = mantissa * 10 + digit; 01113 if (tmp < mantissa) { 01114 if (negative) { 01115 if (-tmp 01116 == std::numeric_limits<int64_t>::min()) 01117 { 01118 // okay 01119 } else { 01120 // data exception -- numeric 01121 // value out of range 01122 overflow = true; 01123 } 01124 } else { 01125 // data exception -- numeric value 01126 // out of range 01127 overflow = true; 01128 } 01129 } 01130 mantissa = tmp; 01131 } else { 01132 overflow = true; 01133 } 01134 01135 if (mantissa != 0) { 01136 mantissa_digits++; 01137 } 01138 } else { 01139 // Decide if ignored digits (after precision is lost) 01140 // causes the final result to be rounded up or not 01141 ignored++; 01142 if (ignored == 1) { 01143 roundup = (digit >= 5); 01144 } 01145 } 01146 parsed = true; 01147 if (decimal_parsed || mantissa != 0) { 01148 parsed_digits++; 01149 } 01150 } else if (!decimal_parsed && (*ptr == '.')) { 01151 // decimal point 01152 ptr++; 01153 decimal_parsed = true; 01154 decimal_position = parsed_digits; 01155 } else if ((*ptr == 'E') || (*ptr == 'e')) { 01156 // parse exponent, move into next state 01157 ptr++; 01158 if (ptr < end) { 01159 if (*ptr == '+' || *ptr == '-' || 01160 (*ptr >= '0' && *ptr <= '9')) { 01161 exponent = SqlStrCastToExact 01162 <CodeUnitBytes, MaxCodeUnitsPerCodePoint> 01163 ((char const * const) ptr, end - ptr, padChar); 01164 } else { 01165 parsed = false; 01166 } 01167 } else { 01168 parsed = false; 01169 } 01170 ptr = end; 01171 break; 01172 } else if (*ptr == padChar) { 01173 // move onto next state, end of number 01174 ptr++; 01175 break; 01176 } else { 01177 // illegal character 01178 parsed = false; 01179 break; 01180 } 01181 } 01182 01183 // STATE: Parse padChar until end or illegal char 01184 while (ptr < end) { 01185 if (*(ptr++) != padChar) { 01186 // unexpected character after end of number 01187 parsed = false; 01188 break; 01189 } 01190 } 01191 if (!parsed) { 01192 // SQL99 Part 2 Section 6.22 General Rule 6.b.i data 01193 // exception -- invalid character value for cast 01194 throw "22018"; 01195 } 01196 01197 // Throw overflow exception only if parse okay 01198 if (overflow) { 01199 // data exception -- numeric value out of range 01200 throw "22003"; 01201 } 01202 01203 if (!decimal_parsed) { 01204 decimal_position = parsed_digits; 01205 } 01206 01207 if (roundup) { 01208 // Check if digits will increase/overflow 01209 if (mantissa == SqlExactMax(mantissa_digits, negative)) { 01210 mantissa_digits++; 01211 } 01212 mantissa++; 01213 } 01214 01215 int parsed_scale = 01216 parsed_digits - ignored - decimal_position - exponent; 01217 01218 if (mantissa_digits - parsed_scale > precision - scale) { 01219 // SQL2003 Part 2 Section 6.12 General Rule 8.a.ii 01220 // data exception -- numeric value out of range 01221 // (if leading significant digits are lost) 01222 throw "22003"; 01223 } 01224 01225 rv = mantissa; 01226 01227 if (scale > parsed_scale) { 01228 int64_t tmp; 01229 for (int i = 0; i < scale - parsed_scale; i++) { 01230 tmp = rv*10; 01231 // Check for overflow 01232 if (tmp < rv) { 01233 // data exception -- numeric value out of range 01234 throw "22003"; 01235 } 01236 rv = tmp; 01237 } 01238 } else if (scale < parsed_scale) { 01239 int adjust_scale = parsed_scale - scale; 01240 for (int i = 0; i < adjust_scale; i++) { 01241 rv = rv / 10; 01242 } 01243 01244 // Do Rounding 01245 int64_t factor = 1; 01246 for (int i = 0; i < adjust_scale; i++) { 01247 factor *= 10; 01248 } 01249 if (mantissa % factor >= factor / 2) { 01250 // Check if digit will increase/overflow 01251 if (rv 01252 == SqlExactMax( 01253 mantissa_digits - adjust_scale, negative)) 01254 { 01255 mantissa_digits++; 01256 if (mantissa_digits - parsed_scale 01257 > precision - scale) { 01258 // SQL2003 Part 2 Section 6.12 General Rule 8.a.ii 01259 // data exception -- numeric value out of range 01260 // (if leading significant digits are lost) 01261 throw "22003"; 01262 } 01263 } 01264 rv++; 01265 } 01266 } 01267 01268 } else if (CodeUnitBytes == 2) { 01269 // TODO: Add UCS2 here 01270 throw std::logic_error("no UCS2"); 01271 } else { 01272 throw std::logic_error("no such encoding"); 01273 } 01274 } else { 01275 throw std::logic_error("no UTF8/16/32"); 01276 } 01277 01278 if (negative) { 01279 return rv * -1; 01280 } else { 01281 return rv; 01282 } 01283 }
int64_t SqlStrCastToExact | ( | char const *const | str, | |
int | strLenBytes, | |||
int | padChar = ' ' | |||
) |
SqlStrCastToExact.
Char & VarChar. Ascii only.
Cast a string to an exact numeric.
Definition at line 867 of file SqlString.h.
References min().
Referenced by SqlStrCastToExact().
00871 { 00872 int64_t rv = 0; 00873 bool negative = false; 00874 00875 if (MaxCodeUnitsPerCodePoint == 1) { 00876 if (CodeUnitBytes == 1) { 00877 // ASCII 00878 // comparison must be unsigned to work for > 128 00879 unsigned char const *ptr = 00880 reinterpret_cast<unsigned char const *>(str); 00881 unsigned char const *end = 00882 reinterpret_cast<unsigned char const *>(str + strLenBytes); 00883 00884 // STATE: parse optional sign, consume leading white space 00885 while (ptr < end) { 00886 if (*ptr == '-') { 00887 // move onto next state, do not allow whitespace 00888 // after -, for example '- 4' is not allowed 00889 negative = true; 00890 ptr++; 00891 break; 00892 } else if (*ptr == '+') { 00893 // move onto next state, do not allow whitespace 00894 // after +, for example '+ 4' is not allowed 00895 ptr++; 00896 break; 00897 } else if (*ptr == padChar) { 00898 // consume leading whitespace 00899 ptr++; 00900 } else if (*ptr >= '0' && *ptr <= '9') { 00901 // found a number. don't advance, move onto next state 00902 break; 00903 } else { 00904 // unexpected character found 00905 // SQL99 Part 2 Section 6.22 General Rule 6.b.i data 00906 // exception -- invalid character value for cast 00907 throw "22018"; 00908 } 00909 } 00910 00911 if (ptr >= end) { 00912 // no number found 00913 // SQL99 Part 2 Section 6.22 General Rule 6.b.i data 00914 // exception -- invalid character value for cast 00915 throw "22018"; 00916 } 00917 00918 // STATE: Parse numbers until padChar, end, or illegal char 00919 bool parsed = false; 00920 bool got_nonzero = false; 00921 bool overflow = false; 00922 int ndigits = 0; 00923 while (ptr < end) { 00924 if (*ptr >= '0' && *ptr <= '9') { 00925 // number 00926 if (*ptr != '0') { 00927 got_nonzero = true; 00928 } 00929 // Only start counting digits after 1st nonzero digit 00930 if (got_nonzero) { 00931 ndigits++; 00932 } 00933 if (ndigits <= 18) { 00934 rv = (rv * 10) + (*(ptr++) - '0'); 00935 } else if (ndigits == 19) { 00936 // Handle 19th digit overflow 00937 int64_t tmp; 00938 tmp = rv * 10 + (*(ptr++) - '0'); 00939 if (tmp < rv) { 00940 if (negative) { 00941 if (-tmp 00942 == std::numeric_limits<int64_t>::min()) 00943 { 00944 // okay 00945 } else { 00946 overflow = true; 00947 } 00948 } else { 00949 overflow = true; 00950 } 00951 } 00952 rv = tmp; 00953 } else { 00954 rv = (rv * 10) + (*(ptr++) - '0'); 00955 overflow = true; 00956 } 00957 parsed = true; 00958 } else if (*ptr == padChar) { 00959 // move onto next state, end of number 00960 ptr++; 00961 break; 00962 } else { 00963 // illegal character 00964 parsed = false; 00965 break; 00966 } 00967 } 00968 00969 // STATE: Parse padChar until end or illegal char 00970 while (ptr < end) { 00971 if (*(ptr++) != padChar) { 00972 // unexpected character after end of number 00973 parsed = false; 00974 break; 00975 } 00976 } 00977 if (!parsed) { 00978 // SQL99 Part 2 Section 6.22 General Rule 6.b.i data 00979 // exception -- invalid character value for cast 00980 throw "22018"; 00981 } 00982 00983 // Throw overflow exception only if parse okay 00984 if (overflow) { 00985 // data exception -- numeric value out of range 00986 throw "22003"; 00987 } 00988 } else if (CodeUnitBytes == 2) { 00989 // TODO: Add UCS2 here 00990 throw std::logic_error("no UCS2"); 00991 } else { 00992 throw std::logic_error("no such encoding"); 00993 } 00994 } else { 00995 throw std::logic_error("no UTF8/16/32"); 00996 } 00997 00998 if (negative) { 00999 return rv * -1; 01000 } else { 01001 return rv; 01002 } 01003 }
int SqlStrCastToVarChar | ( | char * | dest, | |
int | destStorageBytes, | |||
char * | src, | |||
int | srcLenBytes, | |||
int * | rightTruncWarning = NULL , |
|||
int | padchar = ' ' | |||
) |
SqlStrCastToVarChar.
Ascii only.
Pad character code points that require more than one code unit are currently unsupported. Assumes that non-NULL rightTruncWarning points to an int initialized to zero (0).
See SQL99 Part 2 Section 6.22 General Rule 8.c for rules on this cast.
Definition at line 1844 of file SqlString.h.
01851 { 01852 int rv; 01853 01854 if (MaxCodeUnitsPerCodePoint == 1) { 01855 if (CodeUnitBytes == 1) { 01856 // ASCII 01857 if (srcLenBytes <= destStorageBytes) { 01858 memcpy(dest, src, srcLenBytes); 01859 rv = srcLenBytes; 01860 01861 if (srcLenBytes < destStorageBytes) { 01862 memset( 01863 dest + srcLenBytes, 01864 padchar, 01865 destStorageBytes - srcLenBytes); 01866 01867 // Do not alter rv. 01868 } 01869 } else { 01870 memcpy(dest, src, destStorageBytes); 01871 rv = destStorageBytes; 01872 01873 for (char *trunc = src + destStorageBytes, 01874 *end = src + srcLenBytes; 01875 trunc != end; 01876 trunc++) 01877 { 01878 if (*trunc != padchar) { 01879 // Spec says this is just a warning (see SQL99 Part 2 01880 // Section 6.22 General Rule 8.c.ii). Let the caller 01881 // handle it. 01882 if (rightTruncWarning != NULL) { 01883 *rightTruncWarning = 1; 01884 } 01885 } 01886 } 01887 } 01888 } else if (CodeUnitBytes == 2) { 01889 // TODO: Add UCS2 here 01890 throw std::logic_error("no UCS2"); 01891 } else { 01892 throw std::logic_error("no such encoding"); 01893 } 01894 } else { 01895 throw std::logic_error("no UTF8/16/32"); 01896 } 01897 01898 return rv; 01899 }
int FENNEL_CALCULATOR_EXPORT SqlStrCat | ( | char * | dest, | |
int | destStorageBytes, | |||
char const *const | str1, | |||
int | str1LenBytes, | |||
char const *const | str2, | |||
int | str2LenBytes | |||
) |
StrCat.
SQL VARCHAR & CHAR. Ascii & UCS2. dest = str1 || str2. Returns new length in bytes.
This is an optimization for creating a concatenated string from two other strings, eliminating a separate string copy. The assumption is that this is the common case with concatenation. Subsequent concatenations may occur with other form.
If either string is variable width, the result is variable width: per SQL99 Part 2 Section 6.27 Syntax Rule 3.a.i. If both strings are fixed width, the result is fixed width, item ii.
Note: CHAR('1 ') || CHAR('2 ') is CHAR('1 2 ') and is not CHAR('12 ').
When used with CHARs, ignore the return value, and set destLenBytes = destStorageBytes
Definition at line 51 of file SqlString.cpp.
00058 { 00059 if (str1LenBytes + str2LenBytes > destStorageBytes) { 00060 // SQL99 Part 2 Section 22.1 22-001 00061 // "String Data Right truncation" 00062 throw "22001"; 00063 } 00064 00065 memcpy(dest, str1, str1LenBytes); 00066 memcpy(dest + str1LenBytes, str2, str2LenBytes); 00067 return str1LenBytes + str2LenBytes; 00068 }
int FENNEL_CALCULATOR_EXPORT SqlStrCat | ( | char * | dest, | |
int | destStorageBytes, | |||
int | destLenBytes, | |||
char const *const | str, | |||
int | strLenBytes | |||
) |
Strcat.
SQL VARCHAR & CHAR. Ascii & UCS2. dest = dest || str. Returns new length in bytes.
If either string is variable width, the result is variable width: per SQL99 Part 2 Section 6.27 Syntax Rule 3.a.i. If both strings are fixed width, the result is fixed width, per item ii.
Note that CHAR('1 ') || CHAR('2 ') = CHAR('1 2 ') and not CHAR('12 ').
When called repeatedly to cat multiple strings together (e.g. A || B || C), the final destLength must be exactly equal to the defined resulting width. (e.g. width of A+B+C) for both VARCHAR & CHAR. Take care that these length semantics are adhered to in the final result, even though intermediate results (say A || B) may not have the correct length.
When used with CHARs, set strLenBytes to strStorageBytes. On intermediate results set destLenBytes = return value of previous call. Final result should/must have return value == destStorage.
Definition at line 33 of file SqlString.cpp.
00039 { 00040 if (destLenBytes + strLenBytes > destStorageBytes) { 00041 // SQL99 Part 2 Section 22.1 22-001 "String Data Right truncation" 00042 throw "22001"; 00043 } 00044 00045 memcpy(dest + destLenBytes, str, strLenBytes); 00046 return destLenBytes + strLenBytes; 00047 }
int SqlStrCmp | ( | char const *const | str1, | |
int | str1LenBytes, | |||
char const *const | str2, | |||
int | str2LenBytes, | |||
int | trimchar = ' ' | |||
) |
StrCmp.
SQL VARCHAR & CHAR. Ascii, no UCS2 yet.
str1 and str2 can be any combination of VARCHAR and/or CHAR. Supports only PAD SPACE mode. TODO: Support NO PAD mode.
References: SQL2003 Part 2 Section 4.2.2. SQL99 Part 2 Section 4.2.1. SQL2003 Part 2 Section 8.2 General Rule 3. SQL99 Part 2 Section 8.2, General Rule 3. SQL2003 Part 2 Section 10.5 General Rule 2 (default to PAD SPACE). SQL99 Part 2 Section 10.6 General Rule 2: (default to PAD SPACE).
Note: Extending a shorter string with spaces is equivalent to ignoring trailing spaces on both strings, and performing a more conventional strcmp-type operation. For example 'A ' == 'A' becomes 'A ' == 'A ' or equivalently, 'A', 'A'. 'AB ' == 'A' becomes 'AB ' == 'A ' or equivalently, 'AB', 'A'. Extending with spaces is the same as comparison of the longer string with nothing as any non-space character is assumed to be greater than space. Note that this means that passing strings with values less than space will result in some confusion.
Returns -1, 0, 1.
Trim character code points that require more than one code unit are currently unsupported.
Definition at line 188 of file SqlString.h.
References SqlStrCmp_Bin().
00194 { 00195 assert(str1LenBytes >= 0); 00196 assert(str2LenBytes >= 0); 00197 00198 if (CodeUnitBytes == MaxCodeUnitsPerCodePoint) { 00199 if (CodeUnitBytes == 1) { 00200 char const * start = str1; 00201 char const * end = str1 + str1LenBytes; 00202 int str1TrimLenBytes; 00203 int str2TrimLenBytes; 00204 00205 if (end != start) { 00206 end--; 00207 while (end != start && *end == trimchar) { 00208 end--; 00209 } 00210 if (end != start || *end != trimchar) { 00211 end++; 00212 } 00213 } 00214 str1TrimLenBytes = end - start; 00215 00216 start = str2; 00217 end = str2 + str2LenBytes; 00218 00219 if (end != start) { 00220 end--; 00221 while (end != start && *end == trimchar) { 00222 end--; 00223 } 00224 if (end != start || *end != trimchar) { 00225 end++; 00226 } 00227 } 00228 str2TrimLenBytes = end - start; 00229 return SqlStrCmp_Bin( 00230 str1, str1TrimLenBytes, 00231 str2, str2TrimLenBytes); 00232 #if 0 00233 int minLenBytes = str1TrimLenBytes > str2TrimLenBytes ? 00234 str2TrimLenBytes : str1TrimLenBytes; 00235 00236 00237 // To allow 0, "Null", values in string, uses memcmp over 00238 // strcmp. Not strictly needed, may have some future value. 00239 // First, check for differences in "common" length. If same 00240 // values, declare the longer string be declared "larger". 00241 int memc = memcmp(str1, str2, minLenBytes); 00242 if (memc > 0) { 00243 // Normalize to -1, 0, 1 00244 return 1; 00245 } else if (memc < 0) { 00246 // Normalize to -1, 0, 1 00247 return -1; 00248 } else if (str1TrimLenBytes == str2TrimLenBytes) { 00249 // memc == 0 00250 // Equal length & contain same data -> equal 00251 return 0; 00252 } else if (str1TrimLenBytes > str2TrimLenBytes) { 00253 return 1; 00254 } else { 00255 return -1; 00256 } 00257 #endif 00258 } else if (CodeUnitBytes == 2) { 00259 // TODO: Add UCS2 here 00260 throw std::logic_error("no UCS2"); 00261 } else { 00262 throw std::logic_error("no such encoding"); 00263 } 00264 } else { 00265 throw std::logic_error("no UTF8/16/32"); 00266 } 00267 return 0; 00268 }
int FENNEL_CALCULATOR_EXPORT SqlStrCmp_Bin | ( | char const *const | str1, | |
int | str1LenBytes, | |||
char const *const | str2, | |||
int | str2LenBytes | |||
) |
StrCmp.
Binary. See SQL2003 Part 2 Section 4.3.2. As an extension to SQL2003, allow inequalities (>,>=, etc.) Follows byte-wise comparison semantics of memcmp().
Returns -1, 0, 1.
Definition at line 71 of file SqlString.cpp.
Referenced by SqlStrCmp(), strCmpOct(), and SqlStringTest::testSqlStringCmp_Bin_Helper().
00076 { 00077 // First, check for differences in "common" length. If common length 00078 // are contains same values, declare the longer string "larger". 00079 int minLenBytes = 00080 str1LenBytes > str2LenBytes ? str2LenBytes : str1LenBytes; 00081 int memc = memcmp(str1, str2, minLenBytes); 00082 if (memc > 0) { 00083 // Normalize to -1, 0, 1 00084 return 1; 00085 } else if (memc < 0) { 00086 // Normalize to -1, 0, 1 00087 return -1; 00088 } else if (str1LenBytes == str2LenBytes) { 00089 // memc == 0 00090 // Equal length & contain same data -> equal 00091 return 0; 00092 } else if (str1LenBytes > str2LenBytes) { 00093 // Common contains same data, str1 is longer -> str1 > str2 00094 return 1; 00095 } else { 00096 // Common contains same data, str2 is longer -> str2 > str1 00097 return -1; 00098 } 00099 }
int SqlStrCpy_Fix | ( | char * | dest, | |
int | destStorageBytes, | |||
char const *const | str, | |||
int | strLenBytes, | |||
int | padchar = ' ' | |||
) |
StrCpy.
String Copy. Fixed Width / SQL CHAR. Ascii and UCS2.
This routine may not be compliant with the SQL99 standard.
Pad character code points that require more than one code unit are currently unsupported.
Definition at line 278 of file SqlString.h.
00284 { 00285 if (strLenBytes > destStorageBytes) { 00286 // SQL99 22.1 22-001 "String Data Right truncation" 00287 throw "22001"; 00288 } 00289 memcpy(dest, str, strLenBytes); 00290 00291 // pad rest of dest storage 00292 if (MaxCodeUnitsPerCodePoint == 1) { 00293 if (CodeUnitBytes == 1) { 00294 // ASCII 00295 memset(dest + strLenBytes, padchar, destStorageBytes - strLenBytes); 00296 } else if (CodeUnitBytes == 2) { 00297 // UCS2 00298 assert(!(destStorageBytes & 1)); 00299 assert(!(strLenBytes & 1)); 00300 char *ptr = dest + strLenBytes; 00301 char *end = dest + destStorageBytes; 00302 char byte1, byte2; 00303 #ifdef LITTLEENDIAN 00304 byte2 = (padchar >> 8) & 0xff; 00305 byte1 = padchar & 0xff; 00306 #else 00307 byte1 = (padchar >> 8) & 0xff; 00308 byte2 = padchar & 0xff; 00309 #endif 00310 assert(!((end - ptr) & 1)); 00311 while (ptr < end) { 00312 *ptr = byte1; 00313 *(ptr + 1) = byte2; 00314 ptr += 2; 00315 } 00316 } else { 00317 throw std::logic_error("no UCS-4"); 00318 } 00319 } else { 00320 throw std::logic_error("no UTF8/16/32"); 00321 } 00322 return destStorageBytes; 00323 }
int FENNEL_CALCULATOR_EXPORT SqlStrCpy_Var | ( | char * | dest, | |
int | destStorageBytes, | |||
char const *const | str, | |||
int | strLenBytes | |||
) |
StrCpy.
String Copy. Variable Width / VARCHAR. Ascii & UCS2. Returns strLenBytes.
This routine may not be compliant with the SQL99 standard.
May be used for Fixed width strings if strLenBytes == destStorageBytes Otherwise use SqlStrCpy_Fix() to get appropriate padding.
Definition at line 102 of file SqlString.cpp.
Referenced by strCpyA(), and SqlStringTest::testSqlStringCpy_Var().
00107 { 00108 if (strLenBytes > destStorageBytes) { 00109 // SQL99 Part 2 Section 22.1 22-001 00110 // "String Data Right truncation" 00111 throw "22001"; 00112 } 00113 memcpy(dest, str, strLenBytes); 00114 return strLenBytes; 00115 }
int FENNEL_CALCULATOR_EXPORT SqlStrLenBit | ( | int | strLenBytes | ) |
StrLen in bits.
CHAR/VARCHAR. Ascii & UCS2.
Parameter str is ignored for ascii strings.
Definition at line 118 of file SqlString.cpp.
Referenced by strLenBitA(), and SqlStringTest::testSqlStringLenBit().
int SqlStrLenChar | ( | char const *const | str, | |
int | strLenBytes | |||
) |
StrLen in characters.
CHAR/VARCHAR. Ascii & UCS2.
Parameter str is ignored for ascii strings.
Definition at line 353 of file SqlString.h.
00356 { 00357 if (CodeUnitBytes == 1 && MaxCodeUnitsPerCodePoint == 1) { 00358 // ASCII 00359 return strLenBytes; 00360 } else if (CodeUnitBytes == 2 & MaxCodeUnitsPerCodePoint == 1) { 00361 // UCS2 00362 assert(!(strLenBytes & 1)); 00363 return strLenBytes >> 1; 00364 } else { 00365 throw std::logic_error("no UTF8/16/32"); 00366 } 00367 }
int FENNEL_CALCULATOR_EXPORT SqlStrLenOct | ( | int | strLenBytes | ) |
StrLen in octets.
CHAR/VARCHAR. Ascii & UCS2.
Parameter str is ignored for ascii strings.
Definition at line 124 of file SqlString.cpp.
Referenced by strLenOctA(), and SqlStringTest::testSqlStringLenOct().
int SqlStrOverlay | ( | char * | dest, | |
int | destStorageBytes, | |||
char const *const | str, | |||
int | strLenBytes, | |||
char const *const | over, | |||
int | overLenBytes, | |||
int | startChar, | |||
int | lenChar, | |||
int | lenSpecified | |||
) |
Overlay.
CHAR/VARCHAR. Returns new length in bytes. Ascii. No UCS2 yet.
See SQL99 Part 2 Section 6.18 Syntax Rule 10. Overlay is defined in terms of Substring an concatenation. If start is < 1 or length < 0, a substring error may be thrown. Result is VARCHAR, as the result of substring is always VARCHAR, and concatenation results in VARCHAR if any of its operands are VARCHAR. startChar is 1-indexed, as per SQL standard.
Definition at line 385 of file SqlString.h.
00395 { 00396 if (CodeUnitBytes == MaxCodeUnitsPerCodePoint) { 00397 if (CodeUnitBytes == 1) { 00398 if (!lenSpecified) { 00399 lenChar = overLenBytes; 00400 } 00401 if (lenChar < 0 || startChar < 1) { 00402 // Overlay is defined in terms of substring. These conditions 00403 // would, I believe, generate a substring error. Also 00404 // another "reference" sql database gets angry under these 00405 // conditions. Therefore: 00406 // Per SQL99 Part 2 Section 6.18 General Rule 3.d, generate a 00407 // "data exception substring error". SQL99 22.1 22-011 00408 throw "22011"; 00409 } 00410 00411 int leftLenBytes = startChar - 1; // 1-index to 0-index 00412 if (leftLenBytes > strLenBytes) { 00413 leftLenBytes = strLenBytes; 00414 } 00415 char const *rightP = str + leftLenBytes + lenChar; 00416 int rightLenBytes = strLenBytes - (leftLenBytes + lenChar); 00417 if (rightLenBytes < 0) { 00418 rightLenBytes = 0; 00419 } 00420 assert(leftLenBytes >= 0); 00421 assert(rightLenBytes >= 0); 00422 assert(rightP >= str); 00423 00424 if (leftLenBytes + rightLenBytes + overLenBytes 00425 > destStorageBytes) 00426 { 00427 // SQL99 22.1 22-001 "String Data Right truncation" 00428 throw "22001"; 00429 } 00430 00431 char *dp = dest; 00432 00433 memcpy(dp, str, leftLenBytes); 00434 dp += leftLenBytes; 00435 memcpy(dp, over, overLenBytes); 00436 dp += overLenBytes; 00437 memcpy(dp, rightP, rightLenBytes); 00438 dp += rightLenBytes; 00439 00440 return dp - dest; 00441 } else if (CodeUnitBytes == 2) { 00442 // TODO: Add UCS2 here 00443 throw std::logic_error("no UCS2"); 00444 } else { 00445 throw std::logic_error("no such encoding"); } 00446 } else { 00447 throw std::logic_error("no UTF8/16/32"); 00448 } 00449 throw std::logic_error("TODO: Fix this"); 00450 return 0; // TODO: Fix this 00451 }
int SqlStrPos | ( | char const *const | str, | |
int | strLenBytes, | |||
char const *const | find, | |||
int | findLenBytes | |||
) |
Position.
CHAR/VARHCAR. Returns 1-index string position. Ascii. No UCS2.
Returns 0 if not found. Returns 1 if find is zero length. See SQL99 Part 2 Section 6.17 General Rule 2.
Definition at line 459 of file SqlString.h.
00464 { 00465 if (CodeUnitBytes == MaxCodeUnitsPerCodePoint) { 00466 if (CodeUnitBytes == 1) { 00467 // SQL99 Part 2 Section 6.17 General Rule 2.a. 00468 if (!findLenBytes) { 00469 return 1; 00470 } 00471 // SQL99 Part 2 Section 6.17 General Rule 2.c. 00472 if (findLenBytes > strLenBytes) { 00473 return 0; 00474 } 00475 assert(findLenBytes > 0); 00476 assert(strLenBytes > 0); 00477 assert(strLenBytes - findLenBytes >= 0); 00478 00479 register char const * s = str; 00480 char const * end = 1 + s + (strLenBytes - findLenBytes); 00481 00482 while (s < end) { 00483 // search for first char of find 00484 s = reinterpret_cast<char const *>(memchr(s, *find, end - s)); 00485 if (!s) { 00486 return 0; // Case C. 00487 } 00488 if (!memcmp(s, find, findLenBytes)) { 00489 // add 1 to make result 1-indexed. 00490 return (s - str) + 1; // Case B. 00491 } else { 00492 s++; 00493 } 00494 } 00495 return 0; // Case C. 00496 } else if (CodeUnitBytes == 2) { 00497 // TODO: Add UCS2 here 00498 throw std::logic_error("no UCS2"); 00499 } else { 00500 throw std::logic_error("no such encoding"); 00501 } 00502 } else { 00503 throw std::logic_error("no UTF8/16/32"); 00504 } 00505 throw std::logic_error("TODO: Fix this"); 00506 return 0; // TODO: Fix this 00507 }
int SqlStrSubStr | ( | char const ** | dest, | |
int | destStorageBytes, | |||
char const *const | str, | |||
int | strLenBytes, | |||
int | subStartChar, | |||
int | subLenChar, | |||
int | subLenCharSpecified | |||
) |
Substring by reference.
Returns VARCHAR. Accepts CHAR/VARCHAR. Ascii, no UCS2. Sets dest to start of of substring. Returns length of substring.
Note that subStart is 1-indexed, as per SQL99 spec. All substring parameters are handled as signed, as spec implies that they could be negative. Some combinations of subStart and subLenBytes may throw an exception. Results in a VARCHAR. See SQL99 Part 2 Section 6.18 General Rule 3. subStartChar is 1-indexed.
Definition at line 522 of file SqlString.h.
00530 { 00531 if (CodeUnitBytes == MaxCodeUnitsPerCodePoint) { 00532 if (CodeUnitBytes == 1) { 00533 int e; 00534 if (subLenCharSpecified) { 00535 e = subStartChar + subLenChar; 00536 } else { 00537 e = strLenBytes + 1; 00538 if (subStartChar > e) { 00539 e = subStartChar; 00540 } 00541 } 00542 00543 if (e < subStartChar) { 00544 // Per SQL99 Part 2 Section 6.18 General Rule 3.d, generate a 00545 // "data exception substring error". SQL99 22.1 22-011 00546 throw "22011"; 00547 } 00548 00549 if (subStartChar > strLenBytes || e < 1) { 00550 return 0; 00551 } 00552 00553 int s1 = 1; 00554 if (subStartChar > s1) { 00555 s1 = subStartChar; 00556 } 00557 int e1 = strLenBytes + 1; 00558 if (e < e1) { 00559 e1 = e; 00560 } 00561 int l1 = e1 - s1; 00562 00563 if (l1 > destStorageBytes) { 00564 // SQL99 22.1 22-001 "String Data Right truncation" 00565 throw "22001"; 00566 } 00567 if (l1 < 0) { 00568 // Expected behavior not clear. 00569 // "data exception substring error". SQL99 22.1 22-011 00570 throw "22011"; 00571 } 00572 00573 // - 1 converts from 1-indexed to 0-indexed 00574 *dest = str + s1 - 1; 00575 return l1; 00576 } else if (CodeUnitBytes == 2) { 00577 // TODO: Add UCS2 here 00578 throw std::logic_error("no UCS2"); 00579 } else { 00580 throw std::logic_error("no such encoding"); 00581 } 00582 } else { 00583 throw std::logic_error("no UTF8/16/32"); 00584 } 00585 throw std::logic_error("TODO: Fix this"); 00586 return 0; // TODO: Fix this 00587 }
int SqlStrTrim | ( | char const ** | result, | |
char const *const | str, | |||
int | strLenBytes, | |||
int | trimLeft, | |||
int | trimRight, | |||
int | trimchar = ' ' | |||
) |
Trim padding by reference.
CHAR/VARCHAR. Returns new length.
See SQL99 Part 2 Section 6.18 General Rule 8. Results in a VARCHAR. Note: Does not check that result has enough capacity to contain substring as this is irrelevant. If a program depends on the size of result not changing, and this instruction enforcing that invariant -- probably a bad practice anyway -- trouble could result.
Trim character code points that require more than one code unit are currently unsupported.
Definition at line 794 of file SqlString.h.
00801 { 00802 char const * start = str; 00803 char const * end = str + strLenBytes; 00804 assert(strLenBytes >= 0); 00805 00806 if (MaxCodeUnitsPerCodePoint == 1) { 00807 if (CodeUnitBytes == 1) { 00808 // ASCII 00809 // If many pad characters are expected, consider using memrchr() 00810 if (trimLeft) { 00811 while (start != end && *start == trimchar) { 00812 start++; 00813 } 00814 } 00815 if (trimRight && end != start) { 00816 end--; 00817 while (end != start && *end == trimchar) { 00818 end--; 00819 } 00820 if (end != start || *end != trimchar) { 00821 end++; 00822 } 00823 } 00824 } else if (CodeUnitBytes == 2) { 00825 // UCS2 00826 assert(!(strLenBytes & 1)); 00827 char byte1, byte2; 00828 #ifdef LITTLEENDIAN 00829 byte2 = (trimchar >> 8) & 0xff; 00830 byte1 = trimchar & 0xff; 00831 #else 00832 byte1 = (trimchar >> 8) & 0xff; 00833 byte2 = trimchar & 0xff; 00834 #endif 00835 if (trimLeft) { 00836 while (start < end && *start == byte1 && *(start+1) == byte2) { 00837 start += 2; 00838 } 00839 } 00840 if (trimRight && end != start) { 00841 end -= 2; 00842 while (end > start && *end == byte1 && *(end+1) == byte2) { 00843 end -= 2; 00844 } 00845 if (end != start || *end != trimchar) { 00846 end += 2; 00847 } 00848 } 00849 assert(!((end - start) & 1)); 00850 } else { 00851 throw std::logic_error("no such encoding"); 00852 } 00853 } else { 00854 // Note: Potentially UTF16 can be handled by UCS2 code 00855 throw std::logic_error("no UTF8/16/32"); 00856 } 00857 00858 *result = start; 00859 return end - start; 00860 }
int SqlStrTrim | ( | char * | dest, | |
int | destStorageBytes, | |||
char const *const | str, | |||
int | strLenBytes, | |||
int | trimLeft, | |||
int | trimRight, | |||
int | trimchar = ' ' | |||
) |
Trim padding.
CHAR/VARCHAR. Returns new length.
See SQL99 Part 2 Section 6.18 General Rule 8. Results in a VARCHAR.
Trim character code points that require more than one code unit are currently unsupported.
Definition at line 705 of file SqlString.h.
00713 { 00714 char const * start = str; 00715 char const * end = str + strLenBytes; 00716 assert(strLenBytes >= 0); 00717 int newLenBytes; 00718 00719 if (MaxCodeUnitsPerCodePoint == 1) { 00720 if (CodeUnitBytes == 1) { 00721 // ASCII 00722 // If many pad characters are expected, consider using memrchr() 00723 if (trimLeft) { 00724 while (start != end && *start == trimchar) { 00725 start++; 00726 } 00727 } 00728 if (trimRight && end != start) { 00729 end--; 00730 while (end != start && *end == trimchar) { 00731 end--; 00732 } 00733 if (end != start || *end != trimchar) { 00734 end++; 00735 } 00736 } 00737 newLenBytes = end - start; 00738 } else if (CodeUnitBytes == 2) { 00739 // UCS2 00740 assert(!(strLenBytes & 1)); 00741 char byte1, byte2; 00742 #ifdef LITTLEENDIAN 00743 byte2 = (trimchar >> 8) & 0xff; 00744 byte1 = trimchar & 0xff; 00745 #else 00746 byte1 = (trimchar >> 8) & 0xff; 00747 byte2 = trimchar & 0xff; 00748 #endif 00749 if (trimLeft) { 00750 while (start < end && *start == byte1 && *(start+1) == byte2) { 00751 start += 2; 00752 } 00753 } 00754 if (trimRight && end != start) { 00755 end -= 2; 00756 while (end > start && *end == byte1 && *(end+1) == byte2) { 00757 end -= 2; 00758 } 00759 if (end != start || *end != trimchar) { 00760 end += 2; 00761 } 00762 } 00763 newLenBytes = end - start; 00764 assert(!(newLenBytes & 1)); 00765 } else { 00766 throw std::logic_error("no such encoding"); 00767 } 00768 } else { 00769 // Note: Potentially UTF16 can be handled by UCS2 code 00770 throw std::logic_error("no UTF8/16/32"); 00771 } 00772 00773 if (newLenBytes > destStorageBytes) { 00774 // SQL99 22.1 22-001 "String Data Right truncation" 00775 throw "22001"; 00776 } 00777 memcpy(dest, start, newLenBytes); 00778 return newLenBytes; 00779 }