mariadb/storage/connect/tabvir.cpp
Mikhail Chalov 19af1890b5 Use memory safe snprintf() in Connect Engine
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
2022-07-26 16:28:59 +10:00

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 -------------------------- */