/***********************************************************************/ /* Include application header files */ /***********************************************************************/ #include"global.h"// header containing all global declarations. #include"plgdbsem.h"// header containing the DB applic. declarations. #include"preparse.h"// For DATPAR #include"osutil.h" #include"maputil.h" #include"catalog.h" #include"colblk.h" #include"xtable.h"// header of TBX, TDB and TDBASE classes #include"tabcol.h"// header of XTAB and COLUMN classes #include"valblk.h" #include"rcmsg.h" #ifdef ZIP_SUPPORT #include"filamzip.h" #endif// ZIP_SUPPORT #ifdef JAVA_SUPPORT #include"javaconn.h" #endif// JAVA_SUPPORT #ifdef CMGO_SUPPORT #include"cmgoconn.h" #endif// JAVA_SUPPORT
/***********************************************************************/ /* DB static variables. */ /***********************************************************************/ bool Initdone = false; bool plugin = false; // True when called by the XDB plugin handler
extern"C" { externchar version[];
} // extern "C"
//#if defined(_WIN32) //extern CRITICAL_SECTION parsec; // Used calling the Flex parser //#else // !_WIN32 extern pthread_mutex_t parmut; //#endif // !_WIN32
// The debug trace used by the main thread
FILE *pfile = NULL;
MBLOCK Nmblk = {NULL, false, 0, false, NULL}; // Used to init MBLOCK's
/***********************************************************************/ /* Routines called externally and internally by utility routines. */ /***********************************************************************/ bool PlugEvalLike(PGLOBAL, LPCSTR, LPCSTR, bool); bool EvalLikePattern(LPCSTR, LPCSTR); void PlugConvertConstant(PGLOBAL, void* &, short&);
/***********************************************************************/ /* Routines for file IO with error reporting to g->Message */ /* Note: errno and strerror must be called before the message file */ /* is read in the case of XMSG compile. */ /***********************************************************************/ staticvoid global_open_error_msg(GLOBAL *g, int msgid, constchar *path, constchar *mode)
{ int len, rno= (int)errno; char errmsg[256]= "";
strncat(errmsg, strerror(errno), 255);
switch (msgid)
{ case MSGID_CANNOT_OPEN:
len= snprintf(g->Message, sizeof(g->Message) - 1,
MSG(CANNOT_OPEN), // Cannot open %s
path); break;
case MSGID_OPEN_MODE_ERROR:
len= snprintf(g->Message, sizeof(g->Message) - 1,
MSG(OPEN_MODE_ERROR), // "Open(%s) error %d on %s"
mode, rno, path); break;
case MSGID_OPEN_ERROR_AND_STRERROR:
len= snprintf(g->Message, sizeof(g->Message) - 1, //OPEN_ERROR does not work, as it wants mode %d (not %s) //MSG(OPEN_ERROR) "%s",// "Open error %d in mode %d on %s: %s" "Open error %d in mode %s on %s: %s",
rno, mode, path, errmsg); break;
int global_open(GLOBAL *g, int msgid, constchar *path, int flags)
{ int h; if ((h= open(path, flags)) <= 0)
global_open_error_msg(g, msgid, path, ""); return h;
}
int global_open(GLOBAL *g, int msgid, constchar *path, int flags, int mode)
{ int h; if ((h= open(path, flags, mode)) <= 0)
{ char modestr[64];
snprintf(modestr, sizeof(modestr), "%d", mode);
global_open_error_msg(g, msgid, path, modestr);
} return h;
}
DllExport void SetTrc(void)
{ // If tracing is on, debug must be initialized.
debug = pfile;
} // end of SetTrc
/**************************************************************************/ /* SubAllocate the result structure that will contain result data. */ /**************************************************************************/
PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids, int *buftyp, XFLD *fldtyp, unsignedint *length, bool blank, bool nonull)
{ char cname[NAM_LEN+1]; int i;
PCOLRES *pcrp, crp;
PQRYRES qrp;
try { /**********************************************************************/ /* Allocate the structure used to contain the result set. */ /**********************************************************************/
qrp = (PQRYRES)PlugSubAlloc(g, NULL, sizeof(QRYRES));
pcrp = &qrp->Colresp;
qrp->Continued = false;
qrp->Truncated = false;
qrp->Info = false;
qrp->Suball = true;
qrp->Maxres = maxres;
qrp->Maxsize = 0;
qrp->Nblin = 0;
qrp->Nbcol = 0; // will be ncol
qrp->Cursor = 0;
qrp->BadLines = 0;
if (ids > 0) { #ifdefined(XMSG) // Get header from message file
strncpy(cname, PlugReadMessage(g, ids + crp->Ncol, NULL), NAM_LEN);
cname[NAM_LEN] = 0; // for truncated long names #else// !XMSG
GetRcString(ids + crp->Ncol, cname, sizeof(cname)); #endif// !XMSG
crp->Name = (PSZ)PlugDup(g, cname);
} else
crp->Name = NULL; // Will be set by caller
if (fldtyp)
crp->Fld = fldtyp[i]; else
crp->Fld = FLD_NO;
// Allocate the Value Block that will contain data if (crp->Length || nonull)
crp->Kdata = AllocValBlock(g, NULL, crp->Type, maxres,
crp->Length, 0, true, blank, false); else
crp->Kdata = NULL;
/***********************************************************************/ /* Allocate and initialize the new DB User Block. */ /***********************************************************************/
PDBUSER PlgMakeUser(PGLOBAL g)
{
PDBUSER dbuserp;
/***********************************************************************/ /* Extract from a path name the required component. */ /* This function assumes there is enough space in the buffer. */ /***********************************************************************/ char *ExtractFromPath(PGLOBAL g, char *pBuff, char *FileName, OPVAL op)
{ char *drive = NULL, *direc = NULL, *fname = NULL, *ftype = NULL;
switch (op) { // Determine which part to extract #ifdefined(_WIN32) case OP_FDISK: drive = pBuff; break; #endif// !UNIX case OP_FPATH: direc = pBuff; break; case OP_FNAME: fname = pBuff; break; case OP_FTYPE: ftype = pBuff; break; default:
snprintf(g->Message, sizeof(g->Message), MSG(INVALID_OPER), op, "ExtractFromPath"); return NULL;
} // endswitch op
// Now do the extraction
_splitpath(FileName, drive, direc, fname, ftype); return pBuff;
} // end of PlgExtractFromPath
#ifdef NOT_USED /***********************************************************************/ /* Check the occurrence and matching of a pattern against a string. */ /* Because this function is only used for catalog name checking, */ /* it must be case insensitive. */ /***********************************************************************/ staticbool PlugCheckPattern(PGLOBAL g, LPCSTR string, LPCSTR pat)
{ if (pat && strlen(pat)) { // This leaves 2048 bytes (MAX_STR / 2) for each components
LPSTR name = g->Message + MAX_STR / 2;
strlwr(strcpy(name, string));
strlwr(strcpy(g->Message, pat)); // Can be modified by Eval return EvalLikePattern(name, g->Message);
} else returntrue;
} // end of PlugCheckPattern #endif/* NOT_USED */
/***********************************************************************/ /* PlugEvalLike: evaluates a LIKE clause. */ /* Syntaxe: M like P escape C. strg->M, pat->P, C not implemented yet */ /***********************************************************************/ bool PlugEvalLike(PGLOBAL g, LPCSTR strg, LPCSTR pat, bool ci)
{ char *tp, *sp; bool b;
if (trace(2))
htrc("LIKE: strg='%s' pattern='%s'\n", strg, pat);
if (ci) { /* Case insensitive test */ if (strlen(pat) + strlen(strg) + 1 < MAX_STR)
tp = g->Message; elseif (!(tp = newchar[strlen(pat) + strlen(strg) + 2])) {
strcpy(g->Message, MSG(NEW_RETURN_NULL)); throw (int)OP_LIKE;
} /* endif tp */
sp = tp + strlen(pat) + 1;
strlwr(strcpy(tp, pat)); /* Make a lower case copy of pat */
strlwr(strcpy(sp, strg)); /* Make a lower case copy of strg */
} else { /* Case sensitive test */ if (strlen(pat) < MAX_STR) /* In most of the case for small pat */
tp = g->Message; /* Use this as temporary work space. */ elseif (!(tp = newchar[strlen(pat) + 1])) {
strcpy(g->Message, MSG(NEW_RETURN_NULL)); throw (int)OP_LIKE;
} /* endif tp */
strcpy(tp, pat); /* Make a copy to be worked into */
sp = (char*)strg;
} /* endif ci */
b = EvalLikePattern(sp, tp);
if (tp != g->Message) /* If working space was obtained */ delete [] tp; /* by the use of new, delete it. */
return (b);
} /* end of PlugEvalLike */
/***********************************************************************/ /* M and P are variable length character string. If M and P are zero */ /* length strings then the Like predicate is true. */ /* */ /* The Like predicate is true if: */ /* */ /* 1- A substring of M is a sequence of 0 or more contiguous <CR> of M*/ /* and each <CR> of M is part of exactly one substring. */ /* */ /* 2- If the i-th <substring-specifier> of P is an <arbitrary-char- */ /* specifier>, the i-th substring of M is any single <CR>. */ /* */ /* 3- If the i-th <substring-specifier> of P is an <arbitrary-string- */ /* specifier>, then the i-th substring of M is any sequence of zero*/ /* or more <CR>. */ /* */ /* 4- If the i-th <substring-specifier> of P is neither an <arbitrary-*/ /* character-specifier> nor an <arbitrary-string-specifier>, then */ /* the i-th substring of M is equal to that <substring-specifier> */ /* according to the collating sequence of the <like-predicate>, */ /* without the appending of <space-character>, and has the same */ /* length as that <substring-specifier>. */ /* */ /* 5- The number of substrings of M is equal to the number of */ /* <substring-specifiers> of P. */ /* */ /* Otherwise M like P is false. */ /***********************************************************************/ bool EvalLikePattern(LPCSTR sp, LPCSTR tp)
{
LPSTR p; char c;
ssize_t n; bool b, t = false;
/********************************************************************/ /* If pattern is void, Like is true only if string is also void. */ /********************************************************************/ if (!*tp) return (!*sp);
/********************************************************************/ /* Analyse eventual arbitrary specifications ahead of pattern. */ /********************************************************************/ for (p = (LPSTR)tp; p;) switch (*p) { /* it can contain % and/or _ */ case'%': /* An % has been found */
t = true; /* Note eventual character skip */
p++; break; case'_': /* An _ has been found */ if (*sp) { /* If more character in string */
sp++; /* skip it */
p++;
} else returnfalse; /* Like condition is not met */
break; default:
tp = p; /* Point to rest of template */
p = NULL; /* To stop For loop */ break;
} /* endswitch */
if ((p = (LPSTR)strpbrk(tp, "%_"))) /* Get position of next % or _ */
n = p - tp; else
n = strlen(tp); /* Get length of pattern head */
if (n > (signed)strlen(sp)) /* If head is longer than strg */
b = false; /* Like condition is not met */ elseif (n == 0) /* If void <substring-specifier> */
b = (t || !*sp); /* true if % or void strg. */ elseif (!t) { /*******************************************************************/ /* No character to skip, check occurrence of <substring-specifier>*/ /* at the very beginning of remaining string. */ /*******************************************************************/ if (p) { if ((b = !strncmp(sp, tp, n)))
b = EvalLikePattern(sp + n, p);
} else
b = !strcmp(sp, tp); /* strg and tmp heads match */
} else if (p) /*****************************************************************/ /* Here is the case explaining why we need a recursive routine. */ /* The test must be done not only against the first occurrence */ /* of the <substring-specifier> in the remaining string, */ /* but also with all eventual succeeding ones. */ /*****************************************************************/ for (b = false, c = *p; !b && (signed)strlen(sp) >= n; sp++) {
*p = '\0'; /* Separate pattern header */
if ((sp = strstr(sp, tp))) {
*p = c;
b = EvalLikePattern(sp + n, p);
} else {
*p = c;
b = false; break;
} /* endif s */
} /* endfor b, sp */
else {
sp += (strlen(sp) - n);
b = !strcmp(sp, tp);
} /* endif p */
if (trace(2))
htrc(" done: b=%d n=%d sp=%s tp=%s\n",
b, n, (sp) ? sp : "Null", tp);
return (b);
} /* end of EvalLikePattern */
/***********************************************************************/ /* MakeEscape: Escape some characters in a string. */ /***********************************************************************/ char *MakeEscape(PGLOBAL g, char* str, char q)
{ char *bufp; int i, k, n = 0, len = (int)strlen(str);
for (i = 0; i < len; i++) if (str[i] == q || str[i] == '\\')
n++;
if (!n) return str; else
bufp = (char*)PlugSubAlloc(g, NULL, len + n + 1);
for (i = k = 0; i < len; i++) { if (str[i] == q || str[i] == '\\')
bufp[k++] = '\\';
bufp[k++] = str[i];
} // endfor i
bufp[k] = 0; return bufp;
} /* end of MakeEscape */
/***********************************************************************/ /* PlugConvertConstant: convert a Plug constant to an Xobject. */ /***********************************************************************/ void PlugConvertConstant(PGLOBAL g, void* & value, short& type)
{ if (trace(1))
htrc("PlugConvertConstant: value=%p type=%hd\n", value, type);
if (type != TYPE_XOBJECT) {
value = new(g) CONSTANT(g, value, type);
type = TYPE_XOBJECT;
} // endif type
} // end of PlugConvertConstant
/***********************************************************************/ /* Call the Flex preparser to convert a date format to a sscanf input */ /* format and a Strftime output format. Flag if not 0 indicates that */ /* non quoted blanks are not included in the output format. */ /***********************************************************************/
PDTP MakeDateFormat(PGLOBAL g, PCSZ dfmt, bool in, bool out, int flag)
{ int rc;
PDTP pdp = (PDTP)PlugSubAlloc(g, NULL, sizeof(DATPAR));
if (trace(1))
htrc("MakeDateFormat: dfmt=%s\n", dfmt);
if (in)
pdp->InFmt = (char*)PlugSubAlloc(g, NULL, pdp->Outsize);
if (out)
pdp->OutFmt = (char*)PlugSubAlloc(g, NULL, pdp->Outsize);
pdp->Flag = flag;
/*********************************************************************/ /* Call the FLEX generated parser. In multi-threading mode the next */ /* instruction is protected by mutex fmdflex using static variables. */ /*********************************************************************/
pthread_mutex_lock(&parmut);
rc = fmdflex(pdp);
pthread_mutex_unlock(&parmut);
if (trace(1))
htrc("Done: in=%s out=%s rc=%d\n", SVP(pdp->InFmt), SVP(pdp->OutFmt), rc);
return pdp;
} // end of MakeDateFormat
/***********************************************************************/ /* Extract the date from a formatted string according to format. */ /***********************************************************************/ int ExtractDate(char *dts, PDTP pdp, int defy, int val[6])
{
PCSZ fmt; char c, d, e, W[8][12]; int i, k, m, numval; int n, y = 30; bool b = true; // true for null dates
if (pdp)
fmt = pdp->InFmt; else// assume standard MySQL date format
fmt = "%4d-%2d-%2d %2d:%2d:%2d";
if (trace(2))
htrc("ExtractDate: dts=%s fmt=%s defy=%d\n", dts, fmt, defy);
// Set default values for time only use if (defy) { // This may be a default value for year
y = defy;
val[0] = y;
y = (y < 100) ? y : 30;
} else
val[0] = 70;
val[1] = 1;
val[2] = 1;
for (i = 3; i < 6; i++)
val[i] = 0;
numval = 0;
// Get the date field parse it with derived input format
m = sscanf(dts, fmt, W[0], W[1], W[2], W[3], W[4], W[5], W[6], W[7]);
if (m > pdp->Num)
m = pdp->Num;
for (i = 0; i < m; i++) { if ((n = *(int*)W[i]))
b = false;
switch (k = pdp->Index[i]) { case0: if (n < y)
n += 100;
val[0] = n;
numval = MY_MAX(numval, 1); break; case1: case2: case3: case4: case5:
val[k] = n;
numval = MY_MAX(numval, k + 1); break; case -1:
c = toupper(W[i][0]);
d = toupper(W[i][1]);
e = toupper(W[i][2]);
switch (c) { case'J':
n = (d == 'A') ? 1
: (e == 'N') ? 6 : 7; break; case'F': n = 2; break; case'M':
n = (e == 'R') ? 3 : 5; break; case'A':
n = (d == 'P') ? 4 : 8; break; break; case'S': n = 9; break; case'O': n = 10; break; case'N': n = 11; break; case'D': n = 12; break;
} /* endswitch c */
val[1] = n;
numval = MY_MAX(numval, 2); break; case -6:
c = toupper(W[i][0]);
n = val[3] % 12;
/***********************************************************************/ /* Open file routine: the purpose of this routine is to make a list */ /* of all open file so they can be closed in SQLINIT on error jump. */ /***********************************************************************/
FILE *PlugOpenFile(PGLOBAL g, LPCSTR fname, LPCSTR ftype)
{
FILE *fop;
PFBLOCK fp;
PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
// fname may be in volatile memory such as stack
fp->Fname = PlugDup(g, fname);
fp->Count = 1;
fp->Type = TYPE_FB_FILE;
fp->File = fop;
fp->Mode = MODE_ANY; // ???
fp->Next = dbuserp->Openlist;
dbuserp->Openlist = fp;
} /* endif fop */
if (trace(1))
htrc(" returning fop=%p\n", fop);
return (fop);
} // end of PlugOpenFile
/***********************************************************************/ /* Close file routine: the purpose of this routine is to avoid */ /* double closing that freeze the system on some Unix platforms. */ /***********************************************************************/
FILE *PlugReopenFile(PGLOBAL g, PFBLOCK fp, LPCSTR md)
{
FILE *fop;
/***********************************************************************/ /* Close file routine: the purpose of this routine is to avoid */ /* double closing that freeze the system on some Unix platforms. */ /***********************************************************************/ int PlugCloseFile(PGLOBAL g, PFBLOCK fp, bool all)
{ int rc = 0;
// The test on Catalog is to avoid a Windows bug that can make // LoadString in PlugGetMessage to fail in some case if (!dbuserp || !(cat = dbuserp->Catalog)) return;
/*********************************************************************/ /* Close eventually still open/mapped files. */ /*********************************************************************/ for (PFBLOCK fp = dbuserp->Openlist; fp; fp = fp->Next)
PlugCloseFile(g, fp, true);
dbuserp->Openlist = NULL;
if (dofree) { /*******************************************************************/ /* Cleanup any non suballocated memory still not freed. */ /*******************************************************************/ for (PMBLOCK mp = dbuserp->Memlist; mp; mp = mp->Next)
PlgDBfree(*mp);
dbuserp->Memlist = NULL;
/*******************************************************************/ /* If not using permanent storage catalog, reset volatile values. */ /*******************************************************************/
cat->Reset();
/*******************************************************************/ /* This is the place to reset the pointer on domains. */ /*******************************************************************/
dbuserp->Subcor = false;
dbuserp->Step = "New query"; // was STEP(PARSING_QUERY);
dbuserp->ProgMax = dbuserp->ProgCur = dbuserp->ProgSav = 0;
} // endif dofree
} // end of PlugCleanup
#if0 /***********************************************************************/ /* That stupid Windows 98 does not provide this function. */ /***********************************************************************/ bool WritePrivateProfileInt(LPCSTR sec, LPCSTR key, int n, LPCSTR ini)
{ char buf[12];
snprintf(buf, sizeof(buf), "%d", n); return WritePrivateProfileString(sec, key, buf, ini);
} // end of WritePrivateProfileInt
/***********************************************************************/ /* Retrieve a size from an INI file with eventual K or M following. */ /***********************************************************************/ int GetIniSize(char *section, char *key, char *def, char *ini)
{ char c, buff[32]; int i; int n = 0;
if ((i = sscanf(buff, " %d %c ", &n, &c)) == 2) switch (toupper(c)) { case'M':
n *= 1024; case'K':
n *= 1024;
} // endswitch c
if (trace(1))
htrc("GetIniSize: key=%s buff=%s i=%d n=%d\n", key, buff, i, n);
return n;
} // end of GetIniSize
/***********************************************************************/ /* Allocate a string retrieved from an INI file and return its address */ /***********************************************************************/
DllExport PSZ GetIniString(PGLOBAL g, void *mp, LPCSTR sec, LPCSTR key,
LPCSTR def, LPCSTR ini)
{ char buff[_MAX_PATH];
PSZ p; int n, m = sizeof(buff); char *buf = buff;
#ifdefined(_DEBUG)
assert (sec && key); #endif
again:
n = GetPrivateProfileString(sec, key, def, buf, m, ini);
if (n == m - 1) { // String may have been truncated, make sure to have all if (buf != buff) delete [] buf;
m *= 2;
buf = newchar[m]; goto again;
} // endif n
p = (PSZ)PlugSubAlloc(g, mp, n + 1);
if (trace(1))
htrc("GetIniString: sec=%s key=%s buf=%s\n", sec, key, buf);
strcpy(p, buf);
if (buf != buff) delete [] buf;
return p;
} // end of GetIniString #endif// 0
/***********************************************************************/ /* GetAmName: return the name corresponding to an AM code. */ /***********************************************************************/ char *GetAmName(PGLOBAL g, AMT am, void *memp)
{ char *amn= (char*)PlugSubAlloc(g, memp, 16);
switch (am) { case TYPE_AM_ERROR: strcpy(amn, "ERROR"); break; case TYPE_AM_ROWID: strcpy(amn, "ROWID"); break; case TYPE_AM_FILID: strcpy(amn, "FILID"); break; case TYPE_AM_VIEW: strcpy(amn, "VIEW"); break; case TYPE_AM_COUNT: strcpy(amn, "COUNT"); break; case TYPE_AM_DCD: strcpy(amn, "DCD"); break; case TYPE_AM_CMS: strcpy(amn, "CMS"); break; case TYPE_AM_MAP: strcpy(amn, "MAP"); break; case TYPE_AM_FMT: strcpy(amn, "FMT"); break; case TYPE_AM_CSV: strcpy(amn, "CSV"); break; case TYPE_AM_MCV: strcpy(amn, "MCV"); break; case TYPE_AM_DOS: strcpy(amn, "DOS"); break; case TYPE_AM_FIX: strcpy(amn, "FIX"); break; case TYPE_AM_BIN: strcpy(amn, "BIN"); break; case TYPE_AM_VCT: strcpy(amn, "VEC"); break; case TYPE_AM_VMP: strcpy(amn, "VMP"); break; case TYPE_AM_DBF: strcpy(amn, "DBF"); break; case TYPE_AM_QRY: strcpy(amn, "QRY"); break; case TYPE_AM_SQL: strcpy(amn, "SQL"); break; case TYPE_AM_PLG: strcpy(amn, "PLG"); break; case TYPE_AM_PLM: strcpy(amn, "PLM"); break; case TYPE_AM_DOM: strcpy(amn, "DOM"); break; case TYPE_AM_DIR: strcpy(amn, "DIR"); break; case TYPE_AM_ODBC: strcpy(amn, "ODBC"); break; case TYPE_AM_JDBC: strcpy(amn, "JDBC"); break; case TYPE_AM_MAC: strcpy(amn, "MAC"); break; case TYPE_AM_OEM: strcpy(amn, "OEM"); break; case TYPE_AM_OUT: strcpy(amn, "OUT"); break; default: snprintf(amn, 16, "OEM(%d)", am);
} // endswitch am
return amn;
} // end of GetAmName
#ifdefined(SE_CATCH) /***********************************************************************/ /* GetExceptionDesc: return the description of an exception code. */ /***********************************************************************/ char *GetExceptionDesc(PGLOBAL g, unsignedint e)
{ char *p;
switch (e) { case EXCEPTION_GUARD_PAGE:
p = MSG(GUARD_PAGE); break; case EXCEPTION_DATATYPE_MISALIGNMENT:
p = MSG(DATA_MISALIGN); break; case EXCEPTION_BREAKPOINT:
p = MSG(BREAKPOINT); break; case EXCEPTION_SINGLE_STEP:
p = MSG(SINGLE_STEP); break; case EXCEPTION_ACCESS_VIOLATION:
p = MSG(ACCESS_VIOLATN); break; case EXCEPTION_IN_PAGE_ERROR:
p = MSG(PAGE_ERROR); break; case EXCEPTION_INVALID_HANDLE:
p = MSG(INVALID_HANDLE); break; case EXCEPTION_ILLEGAL_INSTRUCTION:
p = MSG(ILLEGAL_INSTR); break; case EXCEPTION_NONCONTINUABLE_EXCEPTION:
p = MSG(NONCONT_EXCEPT); break; case EXCEPTION_INVALID_DISPOSITION:
p = MSG(INVALID_DISP); break; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
p = MSG(ARRAY_BNDS_EXCD); break; case EXCEPTION_FLT_DENORMAL_OPERAND:
p = MSG(FLT_DENORMAL_OP); break; case EXCEPTION_FLT_DIVIDE_BY_ZERO:
p = MSG(FLT_ZERO_DIVIDE); break; case EXCEPTION_FLT_INEXACT_RESULT:
p = MSG(FLT_BAD_RESULT); break; case EXCEPTION_FLT_INVALID_OPERATION:
p = MSG(FLT_INVALID_OP); break; case EXCEPTION_FLT_OVERFLOW:
p = MSG(FLT_OVERFLOW); break; case EXCEPTION_FLT_STACK_CHECK:
p = MSG(FLT_STACK_CHECK); break; case EXCEPTION_FLT_UNDERFLOW:
p = MSG(FLT_UNDERFLOW); break; case EXCEPTION_INT_DIVIDE_BY_ZERO:
p = MSG(INT_ZERO_DIVIDE); break; case EXCEPTION_INT_OVERFLOW:
p = MSG(INT_OVERFLOW); break; case EXCEPTION_PRIV_INSTRUCTION:
p = MSG(PRIV_INSTR); break; case EXCEPTION_STACK_OVERFLOW:
p = MSG(STACK_OVERFLOW); break; case CONTROL_C_EXIT:
p = MSG(CONTROL_C_EXIT); break; case STATUS_NO_MEMORY:
p = MSG(NO_MEMORY); break; default:
p = MSG(UNKNOWN_EXCPT); break;
} // endswitch nSE
return p;
} // end of GetExceptionDesc #endif// SE_CATCH
/***********************************************************************/ /* PlgDBalloc: allocates or suballocates memory conditionally. */ /* If mp.Sub is true at entry, this forces suballocation. */ /* If the memory is allocated, makes an entry in an allocation list */ /* so it can be freed at the normal or error query completion. */ /***********************************************************************/ void *PlgDBalloc(PGLOBAL g, void *area, MBLOCK& mp)
{ //bool b;
size_t maxsub, minsub; void *arp = (area) ? area : g->Sarea;
PPOOLHEADER pph = (PPOOLHEADER)arp;
if (mp.Memp) { // This is a reallocation. If this block is not suballocated, it // was already placed in the chain of memory blocks and we must // not do it again as it can trigger a loop when freeing them. // Note: this works if blocks can be reallocated only once. // Otherwise a new boolean must be added to the block that // indicate that it is chained, or a test on the whole chain be // done to check whether the block is already there. // b = mp.Sub;
mp.Sub = false; // Restrict suballocation to one quarter
} // endif Memp
// Suballoc when possible if mp.Sub is initially true, but leaving // a minimum amount of storage for future operations such as the // optimize recalculation after insert; otherwise // suballoc only if size is smaller than one quarter of free mem.
minsub = (pph->FreeBlk + pph->To_Free + 524248) >> 2;
maxsub = (pph->FreeBlk < minsub) ? 0 : pph->FreeBlk - minsub;
mp.Sub = mp.Size <= ((mp.Sub) ? maxsub : (maxsub >> 2));
if (trace(2))
htrc("PlgDBalloc: in %p size=%zd used=%zd free=%zd sub=%d\n",
arp, mp.Size, pph->To_Free, pph->FreeBlk, mp.Sub);
if (!mp.Sub) { // For allocations greater than one fourth of remaining storage // in the area, do allocate from virtual storage. constchar*v = "malloc"; #ifdefined(_WIN32) if (mp.Size >= BIGMEM) {
v = "VirtualAlloc";
mp.Memp = VirtualAlloc(NULL, mp.Size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
} else #endif
mp.Memp = malloc(mp.Size);
if (trace(8))
htrc("PlgDBalloc: %s(%zd) at %p\n", v, mp.Size, mp.Memp);
if (!mp.Inlist && mp.Memp) { // New allocated block, put it in the memory block chain.
PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
} else // Suballocating is Ok.
mp.Memp = PlugSubAlloc(g, area, mp.Size);
return mp.Memp;
} // end of PlgDBalloc
/***********************************************************************/ /* PlgDBrealloc: reallocates memory conditionally. */ /* Note that this routine can fail only when block size is increased */ /* because otherwise we keep the old storage on failure. */ /***********************************************************************/ void *PlgDBrealloc(PGLOBAL g, void *area, MBLOCK& mp, size_t newsize)
{
MBLOCK m;
if (trace(2))
htrc("PlgDBrealloc: %p size=%zd sub=%d\n", mp.Memp, mp.Size, mp.Sub);
if (newsize == mp.Size) return mp.Memp; // Nothing to do else
m = mp;
if (!mp.Sub && mp.Size < BIGMEM && newsize < BIGMEM) { // Allocation was done by malloc, try to use realloc but // suballoc if newsize is smaller than one quarter of free mem.
size_t maxsub;
PPOOLHEADER pph = (PPOOLHEADER)((area) ? area : g->Sarea);
if ((mp.Sub = (newsize <= (maxsub >> 2)))) {
mp.Memp = PlugSubAlloc(g, area, newsize);
memcpy(mp.Memp, m.Memp, MY_MIN(m.Size, newsize));
PlgDBfree(m); // Free the old block
} else { if (!(mp.Memp = realloc(mp.Memp, newsize))) {
mp = m; // Possible only if newsize > Size return NULL; // Failed
} elseif (trace(8))
htrc("PlgDBrealloc: realloc(%ld) at %p\n", newsize, mp.Memp);
} // endif's
mp.Size = newsize;
} elseif (!mp.Sub || newsize > mp.Size) { // Was suballocated or Allocation was done by VirtualAlloc // Make a new allocation and copy the useful part // Note: DO NOT reset Memp and Sub so we know that this // is a reallocation in PlgDBalloc
mp.Size = newsize;
if (PlgDBalloc(g, area, mp)) {
memcpy(mp.Memp, m.Memp, MY_MIN(m.Size, newsize));
PlgDBfree(m); // Free the old block
} else {
mp = m; // No space to realloc, do nothing
if (newsize > m.Size) return NULL; // Failed
} // endif PlgDBalloc
} // endif's
if (trace(8))
htrc(" newsize=%zd newp=%p sub=%d\n", mp.Size, mp.Memp, mp.Sub);
return mp.Memp;
} // end of PlgDBrealloc
/***********************************************************************/ /* PlgDBfree: free memory if not suballocated. */ /***********************************************************************/ void PlgDBfree(MBLOCK& mp)
{ if (!mp.Sub && mp.Memp) { constchar*v = "free"; #ifdefined(_WIN32) if (mp.Size >= BIGMEM) {
v = "VirtualFree";
VirtualFree(mp.Memp, 0, MEM_RELEASE);
} else #endif
free(mp.Memp);
if (trace(8))
htrc("PlgDBfree: %s(%p) size=%d\n", v, mp.Memp, mp.Size);
} // endif mp
// Do not reset Next to avoid cutting the Mblock chain
mp.Memp = NULL;
mp.Sub = false;
mp.Size = 0;
} // end of PlgDBfree
/***********************************************************************/ /* Program for sub-allocating one item in a storage area. */ /* Note: This function is equivalent to PlugSubAlloc except that in */ /* case of insufficient memory, it returns NULL instead of doing a */ /* throw. The caller must test the return value for error. */ /***********************************************************************/ void *PlgDBSubAlloc(PGLOBAL g, void *memp, size_t size)
{
PPOOLHEADER pph; // Points on area header.
if (!memp) /*******************************************************************/ /* Allocation is to be done in the Sarea. */ /*******************************************************************/
memp = g->Sarea;
//size = ((size + 3) / 4) * 4; /* Round up size to multiple of 4 */
size = ((size + 7) / 8) * 8; /* Round up size to multiple of 8 */
pph = (PPOOLHEADER)memp;
if (size > pph->FreeBlk) { /* Not enough memory left in pool */
snprintf(g->Message, sizeof(g->Message), "Not enough memory in Work area for request of %zd (used=%zd free=%zd)",
size, pph->To_Free, pph->FreeBlk);
if (trace(1))
htrc("%s\n", g->Message);
return NULL;
} // endif size
/*********************************************************************/ /* Do the suballocation the simplest way. */ /*********************************************************************/
memp = MakePtr(memp, pph->To_Free); // Points to suballocated block
pph->To_Free += size; // New offset of pool free block
pph->FreeBlk -= size; // New size of pool free block
if (trace(16))
htrc("Done memp=%p used=%zd free=%zd\n",
memp, pph->To_Free, pph->FreeBlk);
return (memp);
} // end of PlgDBSubAlloc
/***********************************************************************/ /* Program for sub-allocating and copying a string in a storage area. */ /***********************************************************************/ char *PlgDBDup(PGLOBAL g, constchar *str)
{ if (str) { char *sm = (char*)PlgDBSubAlloc(g, NULL, strlen(str) + 1);
t->P1->Old[t->P1->Num] = oldv;
t->P1->New[t->P1->Num++] = newv;
} /* end of NewPointer */
#if0 /***********************************************************************/ /* Compare two files and return 0 if they are identical, else 1. */ /***********************************************************************/ int FileComp(PGLOBAL g, char *file1, char *file2)
{ char *fn[2], *bp[2], buff1[4096], buff2[4096]; int i, k, n[2], h[2] = {-1,-1}; int len[2], rc = -1;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.