mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
19af1890b5
This commit replaces sprintf(buf, ...) with snprintf(buf, sizeof(buf), ...), specifically in the "easy" cases where buf is allocated with a size known at compile time. The changes make sure we are not write outside array/string bounds which will lead to undefined behaviour. In case the code is trying to write outside bounds - safe version of functions simply cut the string messages so we process this gracefully. All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services, Inc. bsonudf.cpp warnings cleanup by Daniel Black Reviewer: Daniel Black
305 lines
11 KiB
C++
305 lines
11 KiB
C++
/************* tdbvir C++ Program Source Code File (.CPP) **************/
|
|
/* PROGRAM NAME: tdbvir.cpp Version 1.2 */
|
|
/* (C) Copyright to the author Olivier BERTRAND 2014-2017 */
|
|
/* This program are the VIR classes DB execution routines. */
|
|
/***********************************************************************/
|
|
|
|
/***********************************************************************/
|
|
/* Include relevant sections of the MariaDB header file. */
|
|
/***********************************************************************/
|
|
#include <my_global.h>
|
|
|
|
/***********************************************************************/
|
|
/* Include application header files: */
|
|
/* global.h is header containing all global declarations. */
|
|
/* plgdbsem.h is header containing the DB application declarations. */
|
|
/* xtable.h is header containing the TDBASE declarations. */
|
|
/* tdbvir.h is header containing the VIR classes declarations. */
|
|
/***********************************************************************/
|
|
#include "global.h"
|
|
#include "plgdbsem.h"
|
|
#include "filter.h"
|
|
#include "xtable.h"
|
|
//#include "reldef.h"
|
|
#include "colblk.h"
|
|
#include "mycat.h" // for FNC_COL
|
|
#include "tabvir.h"
|
|
#include "resource.h" // for IDS_COLUMNS
|
|
|
|
/***********************************************************************/
|
|
/* Return the unique column definition to MariaDB. */
|
|
/***********************************************************************/
|
|
PQRYRES VirColumns(PGLOBAL g, bool info)
|
|
{
|
|
int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING,
|
|
TYPE_INT, TYPE_STRING, TYPE_STRING};
|
|
XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME,
|
|
FLD_PREC, FLD_KEY, FLD_EXTRA};
|
|
unsigned int length[] = {8, 4, 16, 4, 16, 16};
|
|
int i, n, ncol = sizeof(buftyp) / sizeof(int);
|
|
PQRYRES qrp;
|
|
PCOLRES crp;
|
|
|
|
n = (info) ? 0 : 1;
|
|
|
|
/**********************************************************************/
|
|
/* Allocate the structures used to refer to the result set. */
|
|
/**********************************************************************/
|
|
if (!(qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
|
|
buftyp, fldtyp, length, false, true)))
|
|
return NULL;
|
|
|
|
// Some columns must be renamed before info
|
|
for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
|
|
switch (++i) {
|
|
case 5: crp->Name = "Key"; break;
|
|
case 6: crp->Name = "Extra"; break;
|
|
} // endswitch i
|
|
|
|
if (info)
|
|
return qrp;
|
|
|
|
/**********************************************************************/
|
|
/* Now get the results into blocks. */
|
|
/**********************************************************************/
|
|
// Set column name
|
|
crp = qrp->Colresp; // Column_Name
|
|
crp->Kdata->SetValue("n", 0);
|
|
|
|
// Set type, type name, precision
|
|
crp = crp->Next; // Data_Type
|
|
crp->Kdata->SetValue(TYPE_INT, 0);
|
|
|
|
crp = crp->Next; // Type_Name
|
|
crp->Kdata->SetValue(GetTypeName(TYPE_INT), 0);
|
|
|
|
crp = crp->Next; // Precision
|
|
crp->Kdata->SetValue(11, 0);
|
|
|
|
crp = crp->Next; // Key
|
|
crp->Kdata->SetValue("KEY", 0);
|
|
|
|
crp = crp->Next; // Extra
|
|
crp->Kdata->SetValue("SPECIAL=ROWID", 0);
|
|
|
|
qrp->Nblin = 1;
|
|
|
|
/**********************************************************************/
|
|
/* Return the result pointer for use by discovery routines. */
|
|
/**********************************************************************/
|
|
return qrp;
|
|
} // end of VirColumns
|
|
|
|
/* --------------------------- Class VIRDEF --------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* GetTable: makes a new Table Description Block. */
|
|
/***********************************************************************/
|
|
PTDB VIRDEF::GetTable(PGLOBAL g, MODE)
|
|
{
|
|
// Column blocks will be allocated only when needed.
|
|
if (Catfunc == FNC_COL)
|
|
return new(g) TDBVICL(this);
|
|
else
|
|
return new(g) TDBVIR(this);
|
|
|
|
} // end of GetTable
|
|
|
|
/* ------------------------ TDBVIR functions ------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* Implementation of the TDBVIR class. */
|
|
/***********************************************************************/
|
|
TDBVIR::TDBVIR(PVIRDEF tdp) : TDBASE(tdp)
|
|
{
|
|
Size = (tdp->GetElemt()) ? tdp->GetElemt() : 1;
|
|
N = -1;
|
|
} // end of TDBVIR constructor
|
|
|
|
/***********************************************************************/
|
|
/* Analyze the filter and reset the size limit accordingly. */
|
|
/* This is possible when a filter contains predicates implying the */
|
|
/* special column ROWID. Here we just test for when no more good */
|
|
/* records can be met in the remaining of the table. */
|
|
/***********************************************************************/
|
|
int TDBVIR::TestFilter(PFIL filp, bool nop)
|
|
{
|
|
int i, op = filp->GetOpc(), n = 0, type[2] = {0,0};
|
|
int l1 = 0, l2, limit = Size;
|
|
PXOB arg[2] = {NULL,NULL};
|
|
|
|
if (op == OP_GT || op == OP_GE || op == OP_LT || op == OP_LE) {
|
|
for (i = 0; i < 2; i++) {
|
|
arg[i] = filp->Arg(i);
|
|
|
|
switch (filp->GetArgType(i)) {
|
|
case TYPE_CONST:
|
|
if ((l1 = arg[i]->GetIntValue()) >= 0)
|
|
type[i] = 1;
|
|
|
|
break;
|
|
case TYPE_COLBLK:
|
|
if (((PCOL)arg[i])->GetTo_Tdb() == this &&
|
|
((PCOL)arg[i])->GetAmType() == TYPE_AM_ROWID)
|
|
type[i] = 2;
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
} // endswitch ArgType
|
|
|
|
if (!type[i])
|
|
break;
|
|
|
|
n += type[i];
|
|
} // endfor i
|
|
|
|
if (n == 3) {
|
|
// If true it will be ok to delete the filter
|
|
BOOL ok = (filp == To_Filter);
|
|
|
|
if (type[0] == 1)
|
|
// Make it always a Column-op-Value
|
|
switch (op) {
|
|
case OP_GT: op = OP_LT; break;
|
|
case OP_GE: op = OP_LE; break;
|
|
case OP_LT: op = OP_GT; break;
|
|
case OP_LE: op = OP_GE; break;
|
|
} // endswitch op
|
|
|
|
if (!nop) switch (op) {
|
|
case OP_LT: l1--; /* fall through */
|
|
case OP_LE: limit = l1; break;
|
|
default: ok = false;
|
|
} // endswitch op
|
|
|
|
else switch (op) {
|
|
case OP_GE: l1--; /* fall through */
|
|
case OP_GT: limit = l1; break;
|
|
default: ok = false;
|
|
} // endswitch op
|
|
|
|
limit = MY_MIN(MY_MAX(0, limit), Size);
|
|
|
|
// Just one where clause such as Rowid < limit;
|
|
if (ok)
|
|
To_Filter = NULL;
|
|
|
|
} else
|
|
limit = Size;
|
|
|
|
} else if ((op == OP_AND && !nop) || (op == OP_OR && nop)) {
|
|
l1 = TestFilter((PFIL)filp->Arg(0), nop);
|
|
l2 = TestFilter((PFIL)filp->Arg(1), nop);
|
|
limit = MY_MIN(l1, l2);
|
|
} else if (op == OP_NOT)
|
|
limit = TestFilter((PFIL)filp->Arg(0), !nop);
|
|
|
|
return limit;
|
|
} // end of TestFilter
|
|
|
|
/***********************************************************************/
|
|
/* Allocate source column description block. */
|
|
/***********************************************************************/
|
|
PCOL TDBVIR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
|
|
{
|
|
PCOL colp = NULL;
|
|
|
|
if (cdp->IsVirtual()) {
|
|
colp = new(g) VIRCOL(cdp, this, cprec, n);
|
|
} else strcpy(g->Message,
|
|
"Virtual tables accept only special or virtual columns");
|
|
|
|
return colp;
|
|
} // end of MakeCol
|
|
|
|
/***********************************************************************/
|
|
/* VIR Access Method opening routine. */
|
|
/***********************************************************************/
|
|
bool TDBVIR::OpenDB(PGLOBAL g)
|
|
{
|
|
if (Use == USE_OPEN) {
|
|
// Table already open
|
|
N = -1;
|
|
return false;
|
|
} // endif use
|
|
|
|
if (Mode != MODE_READ) {
|
|
strcpy(g->Message, "Virtual tables are read only");
|
|
return true;
|
|
} // endif Mode
|
|
|
|
/*********************************************************************/
|
|
/* Analyze the filter and refine Size accordingly. */
|
|
/*********************************************************************/
|
|
if (To_Filter)
|
|
Size = TestFilter(To_Filter, false);
|
|
|
|
return false;
|
|
} // end of OpenDB
|
|
|
|
/***********************************************************************/
|
|
/* Data Base read routine for the VIR access method. */
|
|
/***********************************************************************/
|
|
int TDBVIR::ReadDB(PGLOBAL)
|
|
{
|
|
return (++N >= Size) ? RC_EF : RC_OK;
|
|
} // end of ReadDB
|
|
|
|
/***********************************************************************/
|
|
/* WriteDB: Data Base write routine for the VIR access methods. */
|
|
/***********************************************************************/
|
|
int TDBVIR::WriteDB(PGLOBAL g)
|
|
{
|
|
snprintf(g->Message, sizeof(g->Message), MSG(VIR_READ_ONLY), To_Def->GetType());
|
|
return RC_FX;
|
|
} // end of WriteDB
|
|
|
|
/***********************************************************************/
|
|
/* Data Base delete line routine for the VIR access methods. */
|
|
/***********************************************************************/
|
|
int TDBVIR::DeleteDB(PGLOBAL g, int)
|
|
{
|
|
snprintf(g->Message, sizeof(g->Message), MSG(VIR_NO_DELETE), To_Def->GetType());
|
|
return RC_FX;
|
|
} // end of DeleteDB
|
|
|
|
/* ---------------------------- VIRCOL ------------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* VIRCOL public constructor. */
|
|
/***********************************************************************/
|
|
VIRCOL::VIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ)
|
|
: COLBLK(cdp, tdbp, i)
|
|
{
|
|
if (cprec) {
|
|
Next = cprec->GetNext();
|
|
cprec->SetNext(this);
|
|
} else {
|
|
Next = tdbp->GetColumns();
|
|
tdbp->SetColumns(this);
|
|
} // endif cprec
|
|
|
|
} // end of VIRCOL constructor
|
|
|
|
/***********************************************************************/
|
|
/* ReadColumn: */
|
|
/***********************************************************************/
|
|
void VIRCOL::ReadColumn(PGLOBAL g)
|
|
{
|
|
// This should never be called
|
|
snprintf(g->Message, sizeof(g->Message), "ReadColumn: Column %s is not virtual", Name);
|
|
throw (int)TYPE_COLBLK;
|
|
} // end of ReadColumn
|
|
|
|
/* ---------------------------TDBVICL class -------------------------- */
|
|
|
|
/***********************************************************************/
|
|
/* GetResult: Get the list the VIRTUAL table columns. */
|
|
/***********************************************************************/
|
|
PQRYRES TDBVICL::GetResult(PGLOBAL g)
|
|
{
|
|
return VirColumns(g, false);
|
|
} // end of GetResult
|
|
|
|
/* ------------------------- End of Virtual -------------------------- */
|