Score
0
Watch 15 Star 9 Fork 5

openLooKeng / hetu-odbc-driverCLGPL-2.1

Create your Gitee Account
Explore and code with more than 5 million developers,Free private repositories !:)
Sign up
The ODBC driver of openLooKeng provides the ODBC interconnection capability for openLooKeng. spread retract

  • C 95.8%
  • CMake 2.7%
  • Shell 0.5%
  • C++ 0.4%
  • Batchfile 0.3%
  • Other 0.3%
Clone or download
ma_helper.c 33.25 KB
Copy Edit Web IDE Raw Blame History
bryanwong authored 2020-06-29 21:58 . openlookeng first commit
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307
/************************************************************************************
Copyright (C) 2013, 2018 MariaDB Corporation AB
Copyright (C) 2018-2020. Huawei Technologies Co., Ltd. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not see <http://www.gnu.org/licenses>
or write to the Free Software Foundation, Inc.,
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
*************************************************************************************/
#include <ma_odbc.h>
#include <stdint.h>
#define MADB_FIELD_IS_BINARY(_field) ((_field)->charsetnr == BINARY_CHARSETNR)
void CloseMultiStatements(MADB_Stmt *Stmt)
{
unsigned int i;
for (i=0; i < STMT_COUNT(Stmt->Query); ++i)
{
MDBUG_C_PRINT(Stmt->Connection, "-->closing %0x", Stmt->MultiStmts[i]);
if (Stmt->MultiStmts[i] != NULL)
{
mysql_stmt_close(Stmt->MultiStmts[i]);
}
}
MADB_FREE(Stmt->MultiStmts);
Stmt->stmt= NULL;
}
MYSQL_STMT* MADB_NewStmtHandle(MADB_Stmt *Stmt)
{
static const my_bool UpdateMaxLength= 1;
MYSQL_STMT* stmt= mysql_stmt_init(Stmt->Connection->mariadb);
if (stmt != NULL)
{
mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &UpdateMaxLength);
}
else
{
MADB_SetError(&Stmt->Error, MADB_ERR_HY001, NULL, 0);
}
return stmt;
}
/* Required, but not sufficient condition */
BOOL QueryIsPossiblyMultistmt(MADB_QUERY *Query)
{
return Query->QueryType != MADB_QUERY_CREATE_PROC && Query->QueryType != MADB_QUERY_CREATE_FUNC &&
Query->QueryType != MADB_QUERY_CREATE_DEFINER && Query->QueryType != MADB_NOT_ATOMIC_BLOCK;
}
/* Trims spaces and/or ';' at the end of query */
int SqlRtrim(char *StmtStr, int Length)
{
if (Length > 0)
{
char *end= StmtStr + Length - 1;
while (end > StmtStr && (isspace(0x000000ff & *end) || *end == ';'))
{
*end= '\0';
--end;
--Length;
}
}
return Length;
}
unsigned int GetMultiStatements(MADB_Stmt *Stmt, BOOL ExecDirect)
{
int i= 0;
unsigned int MaxParams= 0;
char *p= Stmt->Query.RefinedText;
Stmt->MultiStmtNr= 0;
Stmt->MultiStmts= (MYSQL_STMT **)MADB_CALLOC(sizeof(MYSQL_STMT) * STMT_COUNT(Stmt->Query));
while (p < Stmt->Query.RefinedText + Stmt->Query.RefinedLength)
{
Stmt->MultiStmts[i]= i == 0 ? Stmt->stmt : MADB_NewStmtHandle(Stmt);
MDBUG_C_PRINT(Stmt->Connection, "-->inited&preparing %0x(%d,%s)", Stmt->MultiStmts[i], i, p);
if (mysql_stmt_prepare(Stmt->MultiStmts[i], p, (unsigned long)strlen(p)))
{
MADB_SetNativeError(&Stmt->Error, SQL_HANDLE_STMT, Stmt->MultiStmts[i]);
CloseMultiStatements(Stmt);
/* Last paranoid attempt make sure that we did not have a parsing error.
More to preserve "backward-compatibility" - we did this before, but before trying to
prepare "multi-statement". */
if (i == 0 && Stmt->Error.NativeError !=1295 /*ER_UNSUPPORTED_PS*/)
{
Stmt->stmt= MADB_NewStmtHandle(Stmt);
if (mysql_stmt_prepare(Stmt->stmt, STMT_STRING(Stmt), (unsigned long)strlen(STMT_STRING(Stmt))))
{
MADB_STMT_CLOSE_STMT(Stmt);
}
else
{
MADB_DeleteSubqueries(&Stmt->Query);
return 0;
}
}
return 1;
}
if (mysql_stmt_param_count(Stmt->MultiStmts[i]) > MaxParams)
{
MaxParams= mysql_stmt_param_count(Stmt->MultiStmts[i]);
}
p+= strlen(p) + 1;
++i;
}
if (MaxParams)
{
Stmt->params= (MYSQL_BIND *)MADB_CALLOC(sizeof(MYSQL_BIND) * MaxParams);
}
return 0;
}
my_bool MADB_CheckPtrLength(SQLINTEGER MaxLength, char *Ptr, SQLINTEGER NameLen)
{
if(!Ptr)
return TRUE;
if ((NameLen == SQL_NTS && strlen(Ptr) >(size_t) MaxLength) || NameLen > MaxLength)
return FALSE;
return TRUE;
}
int MADB_GetWCharType(int Type)
{
switch (Type) {
case SQL_CHAR:
return SQL_WCHAR;
case SQL_VARCHAR:
return SQL_WVARCHAR;
case SQL_LONGVARCHAR:
return SQL_WLONGVARCHAR;
default:
return Type;
}
}
int MADB_KeyTypeCount(MADB_Dbc *Connection, char *TableName, int KeyFlag)
{
int Count= 0;
unsigned int i;
char StmtStr[1024];
char *p= StmtStr;
char Database[65]= {'\0'};
MADB_Stmt *Stmt= NULL;
MYSQL_FIELD *Field;
Connection->Methods->GetAttr(Connection, SQL_ATTR_CURRENT_CATALOG, Database, 65, NULL, FALSE);
p+= _snprintf(p, 1024, "SELECT * FROM ");
if (Database[0] != '\0')
{
p+= _snprintf(p, sizeof(StmtStr) - strlen(p), "\"%s\".", Database);
}
p+= _snprintf(p, sizeof(StmtStr) - strlen(p), "%s LIMIT 0", TableName);
if (MA_SQLAllocHandle(SQL_HANDLE_STMT, (SQLHANDLE)Connection, (SQLHANDLE*)&Stmt) == SQL_ERROR ||
Stmt->Methods->ExecDirect(Stmt, (char *)StmtStr, SQL_NTS) == SQL_ERROR ||
Stmt->Methods->Fetch(Stmt) == SQL_ERROR)
{
goto end;
}
for (i=0; i < mysql_stmt_field_count(Stmt->stmt); i++)
{
Field= mysql_fetch_field_direct(Stmt->metadata, i);
if (Field->flags & KeyFlag)
{
++Count;
}
}
end:
if (Stmt)
{
Stmt->Methods->StmtFree(Stmt, SQL_DROP);
}
return Count;
}
/* {{{ MADB_CheckODBCType */
BOOL MADB_CheckODBCType(SQLSMALLINT Type)
{
switch(Type)
{
case SQL_C_CHAR:
case SQL_C_WCHAR:
case SQL_C_SSHORT:
case SQL_C_SHORT:
case SQL_C_USHORT:
case SQL_C_SLONG:
case SQL_C_LONG:
case SQL_C_ULONG:
case SQL_C_FLOAT:
case SQL_C_DOUBLE:
case SQL_C_BIT:
case SQL_C_STINYINT:
case SQL_C_TINYINT:
case SQL_C_UTINYINT:
case SQL_C_SBIGINT:
case SQL_C_UBIGINT:
case SQL_C_BINARY:
case SQL_C_TYPE_DATE:
case SQL_C_TYPE_TIME:
case SQL_C_TYPE_TIMESTAMP:
case SQL_C_NUMERIC:
#if (ODBCVER>=0x0350)
case SQL_C_GUID:
#endif
case SQL_C_DEFAULT:
return TRUE;
default:
return FALSE;
}
}
/* {{{ MADB_GetTypeFromConciseType */
SQLSMALLINT MADB_GetTypeFromConciseType(SQLSMALLINT ConciseType)
{
switch (ConciseType)
{
/* todo: support for interval. currently we map only date/time types */
case SQL_C_DATE:
case SQL_C_TIME:
case SQL_C_TIMESTAMP:
case SQL_TYPE_DATE:
case SQL_TYPE_TIME:
case SQL_TYPE_TIMESTAMP:
return SQL_DATETIME;
case SQL_C_INTERVAL_YEAR:
case SQL_C_INTERVAL_YEAR_TO_MONTH:
case SQL_C_INTERVAL_MONTH:
case SQL_C_INTERVAL_DAY:
case SQL_C_INTERVAL_DAY_TO_HOUR:
case SQL_C_INTERVAL_DAY_TO_MINUTE:
case SQL_C_INTERVAL_DAY_TO_SECOND:
case SQL_C_INTERVAL_HOUR:
case SQL_C_INTERVAL_HOUR_TO_MINUTE:
case SQL_C_INTERVAL_HOUR_TO_SECOND:
case SQL_C_INTERVAL_MINUTE:
case SQL_C_INTERVAL_MINUTE_TO_SECOND:
case SQL_C_INTERVAL_SECOND:
return SQL_INTERVAL;
default:
return ConciseType;
}
}
/* }}} */
/* {{{ MADB_GetTypeName */
char *MADB_GetTypeName(MYSQL_FIELD *Field)
{
switch(Field->type) {
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_NEWDECIMAL:
return "decimal";
case MYSQL_TYPE_NULL:
return "null";
case MYSQL_TYPE_TINY:
return (Field->flags & NUM_FLAG) ? "tinyint" : "char";
case MYSQL_TYPE_SHORT:
return "smallint";
case MYSQL_TYPE_LONG:
return "integer";
case MYSQL_TYPE_FLOAT:
return "float";
case MYSQL_TYPE_DOUBLE:
return "double";
case MYSQL_TYPE_TIMESTAMP:
return "timestamp";
case MYSQL_TYPE_LONGLONG:
return "bigint";
case MYSQL_TYPE_INT24:
return "mediumint";
case MYSQL_TYPE_DATE:
return "date";
case MYSQL_TYPE_TIME:
return "time";
case MYSQL_TYPE_DATETIME:
return "datetime";
case MYSQL_TYPE_YEAR:
return "year";
case MYSQL_TYPE_NEWDATE:
return "date";
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_VAR_STRING:
return MADB_FIELD_IS_BINARY(Field) ? "varbinary" : "varchar";
case MYSQL_TYPE_BIT:
return "bit";
case MYSQL_TYPE_ENUM:
return "enum";
case MYSQL_TYPE_SET:
return "set";
case MYSQL_TYPE_TINY_BLOB:
return MADB_FIELD_IS_BINARY(Field) ? "tinyblob" : "tinytext";
case MYSQL_TYPE_MEDIUM_BLOB:
return MADB_FIELD_IS_BINARY(Field) ? "mediumblob" : "mediumtext";
case MYSQL_TYPE_LONG_BLOB:
return MADB_FIELD_IS_BINARY(Field) ? "longblob" : "longtext";
case MYSQL_TYPE_BLOB:
return MADB_FIELD_IS_BINARY(Field) ? "blob" : "text";
case MYSQL_TYPE_STRING:
return MADB_FIELD_IS_BINARY(Field) ? "binary" : "char";
case MYSQL_TYPE_GEOMETRY:
return "geometry";
default:
return "";
}
}
/* }}} */
MYSQL_RES *MADB_GetDefaultColumnValues(MADB_Stmt *Stmt, MYSQL_FIELD *fields)
{
MADB_DynString DynStr;
unsigned int i;
MYSQL_RES *result= NULL;
MADB_InitDynamicString(&DynStr, "SELECT COLUMN_NAME, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='", 512, 512);
if (MADB_DynstrAppend(&DynStr, fields[0].db) ||
MADB_DynstrAppend(&DynStr, "' AND TABLE_NAME='") ||
MADB_DynstrAppend(&DynStr, fields[0].org_table) ||
MADB_DynstrAppend(&DynStr, "' AND COLUMN_NAME IN ("))
goto error;
for (i=0; i < mysql_stmt_field_count(Stmt->stmt); i++)
{
MADB_DescRecord *Rec= MADB_DescGetInternalRecord(Stmt->Ard, i, MADB_DESC_READ);
if (!Rec->inUse || MADB_ColumnIgnoredInAllRows(Stmt->Ard, Rec) == TRUE)
{
continue;
}
if (MADB_DynstrAppend(&DynStr, i > 0 ? ",'" : "'") ||
MADB_DynstrAppend(&DynStr, fields[i].org_name) ||
MADB_DynstrAppend(&DynStr, "'"))
{
goto error;
}
}
if (MADB_DynstrAppend(&DynStr, ") AND COLUMN_DEFAULT IS NOT NULL"))
goto error;
LOCK_MARIADB(Stmt->Connection);
if (mysql_query(Stmt->Connection->mariadb, DynStr.str))
goto error;
result= mysql_store_result(Stmt->Connection->mariadb);
error:
UNLOCK_MARIADB(Stmt->Connection);
MADB_DynstrFree(&DynStr);
return result;
}
char *MADB_GetDefaultColumnValue(MYSQL_RES *res, const char *Column)
{
MYSQL_ROW row;
if (res == NULL || !res->row_count)
return NULL;
mysql_data_seek(res, 0);
while ((row= mysql_fetch_row(res)))
{
if (_stricmp(row[0], Column) == 0)
return _strdup(row[1]);
}
return NULL;
}
SQLLEN MADB_GetDataSize(SQLSMALLINT SqlType, SQLLEN OctetLength, BOOL Unsigned,
SQLSMALLINT Precision, SQLSMALLINT Scale, unsigned int CharMaxLen)
{
switch(SqlType)
{
case SQL_BIT:
return 1;
case SQL_TINYINT:
return 3;
case SQL_SMALLINT:
return 5;
case SQL_INTEGER:
return 10;
case SQL_BIGINT:
return 20 - test(Unsigned != FALSE);
case SQL_REAL:
return 7;
case SQL_DOUBLE:
case SQL_FLOAT:
return 15;
case SQL_DECIMAL:
case SQL_NUMERIC:
return Precision;
case SQL_TYPE_DATE:
return SQL_DATE_LEN;
case SQL_TYPE_TIME:
return SQL_TIME_LEN + MADB_FRACTIONAL_PART(Scale);
case SQL_TYPE_TIMESTAMP:
return SQL_TIMESTAMP_LEN + MADB_FRACTIONAL_PART(Scale);
case SQL_BINARY:
case SQL_VARBINARY:
case SQL_LONGVARBINARY:
return OctetLength;
case SQL_GUID:
return 36;;
default:
{
if (CharMaxLen < 2/*i.e.0||1*/)
{
return OctetLength;
}
else
{
return OctetLength/CharMaxLen;
}
}
}
}
/* {{{ MADB_GetDisplaySize */
size_t MADB_GetDisplaySize(MYSQL_FIELD *Field, MARIADB_CHARSET_INFO *charset)
{
/* Todo: check these values with output from mysql --with-columntype-info */
switch (Field->type) {
case MYSQL_TYPE_NULL:
return 1;
case MYSQL_TYPE_BIT:
return (Field->length == 1) ? 1 : (Field->length + 7) / 8 * 2;
case MYSQL_TYPE_TINY:
return 4 - test(Field->flags & UNSIGNED_FLAG);
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_YEAR:
return 6 - test(Field->flags & UNSIGNED_FLAG);
case MYSQL_TYPE_INT24:
return 9 - test(Field->flags & UNSIGNED_FLAG);
case MYSQL_TYPE_LONG:
return 11 - test(Field->flags & UNSIGNED_FLAG);
case MYSQL_TYPE_LONGLONG:
return 20;
case MYSQL_TYPE_DOUBLE:
return 15;
case MYSQL_TYPE_FLOAT:
return 7;
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_NEWDECIMAL:
{
/* The edge case like decimal(1,1)*/
size_t Precision= Field->length - test((Field->flags & UNSIGNED_FLAG) == 0) - test(Field->decimals != 0);
return Field->length + test(Precision == Field->decimals);
}
case MYSQL_TYPE_DATE:
return SQL_DATE_LEN; /* YYYY-MM-DD */
case MYSQL_TYPE_TIME:
return SQL_TIME_LEN + MADB_FRACTIONAL_PART(Field->decimals); /* HH:MM:SS.ffffff */
case MYSQL_TYPE_NEWDATE:
case MYSQL_TYPE_TIMESTAMP:
case MYSQL_TYPE_DATETIME:
return SQL_TIMESTAMP_LEN + MADB_FRACTIONAL_PART(Field->decimals);
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_GEOMETRY:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_SET:
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_VAR_STRING:
{
if (MADB_FIELD_IS_BINARY(Field))
{
return Field->length*2; /* ODBC specs says we should give 2 characters per byte to display binaray data in hex form */
}
else if (charset == NULL || charset->char_maxlen < 2/*i.e.0||1*/)
{
return Field->length;
}
else
{
return Field->length/charset->char_maxlen;
}
}
default:
return SQL_NO_TOTAL;
}
}
/* }}} */
/* {{{ MADB_GetOctetLength */
size_t MADB_GetOctetLength(MYSQL_FIELD *Field, unsigned short MaxCharLen)
{
size_t Length= MIN(MADB_INT_MAX32, Field->length);
switch (Field->type) {
case MYSQL_TYPE_NULL:
return 1;
case MYSQL_TYPE_BIT:
return (Field->length + 7) / 8;
case MYSQL_TYPE_TINY:
return 1;
case MYSQL_TYPE_YEAR:
case MYSQL_TYPE_SHORT:
return 2;
case MYSQL_TYPE_INT24:
return 3;
case MYSQL_TYPE_LONG:
return 4;
case MYSQL_TYPE_LONGLONG:
return 8;
case MYSQL_TYPE_DOUBLE:
return 8;
case MYSQL_TYPE_FLOAT:
return 4;
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_NEWDECIMAL:
{
/* The edge case like decimal(1,1)*/
size_t Precision= Field->length - test((Field->flags & UNSIGNED_FLAG) == 0) - test(Field->decimals != 0);
return Field->length + test(Precision == Field->decimals);
}
case MYSQL_TYPE_DATE:
return sizeof(SQL_DATE_STRUCT);
case MYSQL_TYPE_TIME:
return sizeof(SQL_TIME_STRUCT);
case MYSQL_TYPE_NEWDATE:
case MYSQL_TYPE_TIMESTAMP:
case MYSQL_TYPE_DATETIME:
return sizeof(SQL_TIMESTAMP_STRUCT);
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_GEOMETRY:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_TINY_BLOB:
return Length;
case MYSQL_TYPE_SET:
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_VAR_STRING:
return Length; /* Field->length is calculated using current charset */
default:
return SQL_NO_TOTAL;
}
}
/* }}} */
/* {{{ MADB_GetDefaultType */
int MADB_GetDefaultType(int SQLDataType)
{
switch(SQLDataType)
{
case SQL_BIGINT:
return SQL_C_SBIGINT;
case SQL_BINARY:
return SQL_C_BINARY;
case SQL_BIT:
return SQL_C_BIT;
case SQL_CHAR:
return SQL_C_CHAR;
case SQL_DATE:
case SQL_TYPE_DATE:
return SQL_C_DATE;
case SQL_DECIMAL:
return SQL_C_CHAR;
case SQL_DOUBLE:
return SQL_C_DOUBLE;
case SQL_FLOAT:
return SQL_C_FLOAT;
case SQL_INTEGER:
return SQL_C_LONG;
case SQL_LONGVARBINARY:
return SQL_C_BINARY;
case SQL_LONGVARCHAR:
return SQL_C_CHAR;
case SQL_NUMERIC:
return SQL_C_CHAR;
case SQL_REAL:
return SQL_C_FLOAT;
case SQL_SMALLINT:
return SQL_C_SHORT;
case SQL_TIME:
case SQL_TYPE_TIME:
return SQL_C_TIME;
case SQL_TIMESTAMP:
case SQL_TYPE_TIMESTAMP:
return SQL_C_TIMESTAMP;
case SQL_TINYINT:
return SQL_C_TINYINT;
case SQL_VARBINARY:
return SQL_C_BINARY;
case SQL_VARCHAR:
return SQL_C_CHAR;
default:
return SQL_C_CHAR;
}
}
/* }}} */
/* {{{ MapMariadDbToOdbcType */
/* It's not quite right to mix here C and SQL types, even though constants are sort of equal */
SQLSMALLINT MapMariadDbToOdbcType(MYSQL_FIELD *field)
{
switch (field->type) {
case MYSQL_TYPE_BIT:
if (field->length > 1)
return SQL_BINARY;
return SQL_BIT;
case MYSQL_TYPE_NULL:
return SQL_VARCHAR;
case MYSQL_TYPE_TINY:
return field->flags & NUM_FLAG ? SQL_TINYINT : SQL_CHAR;
case MYSQL_TYPE_YEAR:
case MYSQL_TYPE_SHORT:
return SQL_SMALLINT;
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
return SQL_INTEGER;
case MYSQL_TYPE_FLOAT:
return SQL_REAL;
case MYSQL_TYPE_DOUBLE:
return SQL_DOUBLE;
case MYSQL_TYPE_TIMESTAMP:
case MYSQL_TYPE_DATETIME:
return SQL_TYPE_TIMESTAMP;
case MYSQL_TYPE_NEWDATE:
case MYSQL_TYPE_DATE:
return SQL_TYPE_DATE;
case MYSQL_TYPE_TIME:
return SQL_TYPE_TIME;
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
return MADB_FIELD_IS_BINARY(field) ? SQL_LONGVARBINARY : SQL_LONGVARCHAR;
case MYSQL_TYPE_LONGLONG:
return SQL_BIGINT;
case MYSQL_TYPE_STRING:
return MADB_FIELD_IS_BINARY(field) ? SQL_BINARY : SQL_CHAR;
case MYSQL_TYPE_VAR_STRING:
return MADB_FIELD_IS_BINARY(field) ? SQL_VARBINARY : SQL_VARCHAR;
case MYSQL_TYPE_SET:
case MYSQL_TYPE_ENUM:
return SQL_CHAR;
case MYSQL_TYPE_GEOMETRY:
return SQL_LONGVARBINARY;
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_NEWDECIMAL:
return SQL_DECIMAL;
default:
return SQL_UNKNOWN_TYPE;
}
}
/* }}} */
/* {{{ MADB_GetTypeLength */
size_t MADB_GetTypeLength(SQLINTEGER SqlDataType, size_t Length)
{
switch(SqlDataType)
{
case SQL_C_BIT:
case SQL_C_TINYINT:
case SQL_C_STINYINT:
case SQL_C_UTINYINT:
return 1;
case SQL_C_SHORT:
case SQL_C_SSHORT:
case SQL_C_USHORT:
return 2;
case SQL_C_LONG:
case SQL_C_SLONG:
case SQL_C_ULONG:
return sizeof(SQLINTEGER);
case SQL_C_UBIGINT:
case SQL_C_SBIGINT:
return sizeof(long long);
case SQL_C_DOUBLE:
return sizeof(SQLDOUBLE);
case SQL_C_FLOAT:
return sizeof(SQLFLOAT);
case SQL_C_NUMERIC:
return sizeof(SQL_NUMERIC_STRUCT);
case SQL_C_TYPE_TIME:
case SQL_C_TIME:
return sizeof(SQL_TIME_STRUCT);
case SQL_C_TYPE_DATE:
case SQL_C_DATE:
return sizeof(SQL_DATE_STRUCT);
case SQL_C_TYPE_TIMESTAMP:
case SQL_C_TIMESTAMP:
return sizeof(SQL_TIMESTAMP_STRUCT);
default:
return Length;
}
}
/* }}} */
/* {{{ MADB_GetMaDBTypeAndLength */
int MADB_GetMaDBTypeAndLength(SQLINTEGER SqlDataType, my_bool *Unsigned, unsigned long *Length)
{
*Unsigned= 0;
switch(SqlDataType)
{
case SQL_C_BIT:
case SQL_C_TINYINT:
case SQL_C_STINYINT:
case SQL_C_UTINYINT:
*Length= 1;
*Unsigned= (SqlDataType == SQL_C_UTINYINT);
return MYSQL_TYPE_TINY;
case SQL_C_SHORT:
case SQL_C_SSHORT:
case SQL_C_USHORT:
*Length= 2;
*Unsigned= (SqlDataType == SQL_C_USHORT);
return MYSQL_TYPE_SHORT;
case SQL_C_LONG:
case SQL_C_SLONG:
case SQL_C_ULONG:
*Length= sizeof(SQLINTEGER);
*Unsigned= (SqlDataType == SQL_C_ULONG);
return MYSQL_TYPE_LONG;
case SQL_C_UBIGINT:
case SQL_C_SBIGINT:
*Length= sizeof(long long);
*Unsigned= (SqlDataType == SQL_C_UBIGINT);
return MYSQL_TYPE_LONGLONG;
case SQL_C_DOUBLE:
*Length= sizeof(SQLDOUBLE);
return MYSQL_TYPE_DOUBLE;
case SQL_C_FLOAT:
*Length =sizeof(SQLFLOAT);
return MYSQL_TYPE_FLOAT;
case SQL_C_NUMERIC:
/**Length= sizeof(SQL_NUMERIC_STRUCT);*/
return MYSQL_TYPE_DECIMAL;
case SQL_C_TYPE_TIME:
case SQL_C_TIME:
*Length= sizeof(SQL_TIME_STRUCT);
return MYSQL_TYPE_TIME;
case SQL_C_TYPE_DATE:
case SQL_C_DATE:
*Length= sizeof(SQL_DATE_STRUCT);
return MYSQL_TYPE_DATE;
case SQL_C_TYPE_TIMESTAMP:
case SQL_C_TIMESTAMP:
*Length= sizeof(SQL_TIMESTAMP_STRUCT);
return MYSQL_TYPE_TIMESTAMP;
case SQL_C_INTERVAL_HOUR_TO_MINUTE:
case SQL_C_INTERVAL_HOUR_TO_SECOND:
*Length= sizeof(SQL_INTERVAL_STRUCT);
return MYSQL_TYPE_TIME;
case SQL_C_CHAR:
return MYSQL_TYPE_STRING;
default:
return MYSQL_TYPE_BLOB;
}
}
/* }}} */
void MADB_CopyOdbcTsToMadbTime(SQL_TIMESTAMP_STRUCT *Src, MYSQL_TIME *Dst)
{
Dst->year= Src->year;
Dst->month= Src->month;
Dst->day= Src->day;
Dst->hour= Src->hour;
Dst->minute= Src->minute;
Dst->second= Src->second;
Dst->second_part= Src->fraction / 1000;
}
void MADB_CopyMadbTimeToOdbcTs(MYSQL_TIME *Src, SQL_TIMESTAMP_STRUCT *Dst)
{
Dst->year= (int)Src->year;
Dst->month= Src->month;
Dst->day= Src->day;
Dst->hour= Src->hour;
Dst->minute= Src->minute;
Dst->second= Src->second;
Dst->fraction= Src->second_part*1000;
}
SQLRETURN MADB_CopyMadbTimestamp(MADB_Stmt *Stmt, MYSQL_TIME *tm, SQLPOINTER DataPtr, SQLLEN *Length, SQLLEN *Ind,
SQLSMALLINT CType, SQLSMALLINT SqlType)
{
SQLLEN Dummy;
Length= Length == NULL ? &Dummy : Length;
switch(CType)
{
case SQL_C_TIMESTAMP:
case SQL_C_TYPE_TIMESTAMP:
{
SQL_TIMESTAMP_STRUCT *ts= (SQL_TIMESTAMP_STRUCT *)DataPtr;
if (ts != NULL)
{
/* If time converted to timestamp - fraction is set to 0, date is set to current date */
if (SqlType == SQL_TIME || SqlType == SQL_TYPE_TIME)
{
time_t sec_time;
struct tm * cur_tm;
sec_time= time(NULL);
cur_tm= localtime(&sec_time);
ts->year= 1900 + cur_tm->tm_year;
ts->month= cur_tm->tm_mon + 1;
ts->day= cur_tm->tm_mday;
ts->fraction= 0;
}
else
{
ts->year= (int)tm->year;
ts->month= tm->month;
ts->day= tm->day;
ts->fraction= tm->second_part * 1000;
}
ts->hour= tm->hour;
ts->minute= tm->minute;
ts->second= tm->second;
if (ts->year + ts->month + ts->day + ts->hour + ts->minute + ts->fraction + ts->second == 0)
{
if (Ind != NULL)
{
*Ind= SQL_NULL_DATA;
}
else
{
return MADB_SetError(&Stmt->Error, MADB_ERR_22002, NULL, 0);
}
break;
}
}
*Length= sizeof(SQL_TIMESTAMP_STRUCT);
}
break;
case SQL_C_TIME:
case SQL_C_TYPE_TIME:
{
SQL_TIME_STRUCT *ts= (SQL_TIME_STRUCT *)DataPtr;
if (ts != NULL)
{
/* tm(buffer from MYSQL_BIND) can be NULL. And that happens if ts(app's buffer) is null */
if (!VALID_TIME(tm))
{
return MADB_SetError(&Stmt->Error, MADB_ERR_22007, NULL, 0);
}
ts->hour= tm->hour;
ts->minute= tm->minute;
ts->second= tm->second;
*Length= sizeof(SQL_TIME_STRUCT);
if (tm->second_part)
{
return MADB_SetError(&Stmt->Error, MADB_ERR_01S07, NULL, 0);
}
}
}
break;
case SQL_C_DATE:
case SQL_TYPE_DATE:
{
SQL_DATE_STRUCT *ts= (SQL_DATE_STRUCT *)DataPtr;
if (ts != NULL)
{
ts->year= (int)tm->year;
ts->month= tm->month;
ts->day= tm->day;
if (ts->year + ts->month + ts->day == 0)
{
if (Ind != NULL)
{
*Ind= SQL_NULL_DATA;
}
else
{
return MADB_SetError(&Stmt->Error, MADB_ERR_22002, NULL, 0);
}
break;
}
}
*Length= sizeof(SQL_DATE_STRUCT);
}
break;
}
return SQL_SUCCESS;
}
void *GetBindOffset(MADB_Desc *Desc, MADB_DescRecord *Record, void *Ptr, SQLULEN RowNumber, size_t PtrSize)
{
size_t BindOffset= 0;
/* This is not quite clear - I'd imagine, that if BindOffset is set, then Ptr can be NULL.
Makes perfect sense in case of row-based binding - setting pointers to offset in structure, and BindOffset to the begin of array.
One of members would have 0 offset then. But specs are rather against that, and other drivers also don't support such interpretation */
if (Ptr == NULL)
{
return NULL;
}
if (Desc->Header.BindOffsetPtr != NULL)
{
BindOffset= (size_t)*Desc->Header.BindOffsetPtr;
}
/* row wise binding */
if (Desc->Header.BindType == SQL_BIND_BY_COLUMN ||
Desc->Header.BindType == SQL_PARAM_BIND_BY_COLUMN)
{
BindOffset+= PtrSize * RowNumber;
}
else
{
BindOffset+= Desc->Header.BindType * RowNumber;
}
return (char *)Ptr + BindOffset;
}
/* Checking if column ignored in all bound rows. Should hel*/
BOOL MADB_ColumnIgnoredInAllRows(MADB_Desc *Desc, MADB_DescRecord *Rec)
{
SQLULEN row;
SQLLEN *IndicatorPtr;
for (row= 0; row < Desc->Header.ArraySize; ++row)
{
IndicatorPtr= (SQLLEN *)GetBindOffset(Desc, Rec, Rec->IndicatorPtr, row, sizeof(SQLLEN));
if (IndicatorPtr == NULL || *IndicatorPtr != SQL_COLUMN_IGNORE)
{
return FALSE;
}
}
return TRUE;
}
void MADB_NumericInit(SQL_NUMERIC_STRUCT *number, MADB_DescRecord *Ard)
{
if (!number)
return;
number->precision= (SQLCHAR)Ard->Precision;
number->scale= (SQLCHAR)Ard->Scale;
memset(number->val, 0, sizeof(number->val));
}
/* {{{ MADB_CharToSQLNumeric */
int MADB_CharToSQLNumeric(char *buffer, MADB_Desc *Ard, MADB_DescRecord *ArdRecord, SQL_NUMERIC_STRUCT *dst_buffer, unsigned long RowNumber)
{
char *p;
SQL_NUMERIC_STRUCT *number= dst_buffer != NULL ? dst_buffer :
(SQL_NUMERIC_STRUCT *)GetBindOffset(Ard, ArdRecord, ArdRecord->DataPtr, RowNumber, ArdRecord->OctetLength);
int ret= 0;
if (!buffer || !number)
return ret;
p= trim(buffer);
MADB_NumericInit(number, ArdRecord);
if (!(number->sign= (*p=='-') ? 0 : 1))
p++;
if (!*p)
return FALSE;
if (number->precision == 0)
{
number->precision= MADB_DEFAULT_PRECISION;
}
while (*p=='0')
{
p++;
}
if (*p)
{
int i;
int bit, hval, tv, dig, sta, olen;
int tmp_digit= 0;
int leading_zeros= 0;
char *dot= strchr(p, '.');
char digits[100];
short digits_count= 0;
/* Overflow check */
if (number->precision > 0 && (dot - p) > number->precision)
return MADB_ERR_22003;
if (dot && number->scale > 0)
{
short digits_total= 0,
digits_significant= 0;
digits_count= (short)(dot - p);
memcpy(digits, p, digits_count);
p= dot + 1;
while (*p)
{
/* ignore non numbers */
if (!isdigit(0x000000ff & *p))
break;
digits_total++;
/* ignore trailing zeros */
if (*p != '0')
{
digits_significant= digits_total;
}
p++;
}
if (digits_count + number->scale > number->precision)
{
int i;
/* if digits are zero there is no overflow */
for (i=1; i <= digits_significant; i++)
{
p= dot + i;
if (*p != '0')
return MADB_ERR_22003;
}
}
memcpy(digits + digits_count, dot + 1, digits_significant);
if (number->scale > digits_significant)
{
for (i= digits_count + digits_significant; i < number->precision && i < digits_count +number->scale; ++i)
{
digits[i]= '0';
}
digits_significant= number->scale;
}
digits_count+= digits_significant;
}
else
{
char *start= p;
while (*p && isdigit(0x000000ff & *p))
p++;
/* check overflow */
if (p - start > number->precision)
{
return MADB_ERR_22003;
}
digits_count= (short)(p - start);
memcpy(digits, start, digits_count);
number->scale= ArdRecord->Scale ? ArdRecord->Scale : 0;
}
/* Rounding */
if (number->scale < 0)
{
int64_t OldVal, Val;
int64_t RoundNumber= (int64_t)pow(10.0, -number->scale);
digits[number->precision]= 0;
Val= _atoi64(digits);
OldVal= Val;
Val= (Val + RoundNumber / 2) / RoundNumber * RoundNumber;
if (OldVal != Val)
return MADB_ERR_22003;
_snprintf(digits, sizeof(digits), "%lld", Val);
digits_count= (short)strlen(digits);
if (digits_count > number->precision)
return MADB_ERR_22003;
}
digits_count= MIN(digits_count, MADB_DEFAULT_PRECISION);
for (hval = 0, bit = 1L, sta = 0, olen = 0; sta < digits_count;)
{
for (dig = 0, i = sta; i < digits_count; i++)
{
tv = dig * 10 + digits[i] - '0';
dig = tv % 2;
digits[i] = tv / 2 + '0';
if (i == sta && tv < 2)
sta++;
}
if (dig > 0)
hval |= bit;
bit <<= 1;
if (bit >= (1L << 8))
{
number->val[olen++] = hval;
hval = 0;
bit = 1L;
if (olen >= SQL_MAX_NUMERIC_LEN - 1)
{
//number->scale = sta - number->precision;
//ret= MADB_ERR_22003;
break;
}
}
}
if (hval && olen < SQL_MAX_NUMERIC_LEN - 1)
{
number->val[olen++] = hval;
}
}
return ret;
}
/* {{{ MADB_GetHexString */
size_t MADB_GetHexString(char *BinaryBuffer, size_t BinaryLength,
char *HexBuffer, size_t HexLength)
{
const char HexDigits[]= "0123456789ABCDEF";
char *Start= HexBuffer;
size_t CurrentLength= HexLength;
if (!HexBuffer || !BinaryBuffer)
return 0;
while (BinaryLength-- && CurrentLength > 2)
{
*HexBuffer++=HexDigits[*BinaryBuffer >> 4];
*HexBuffer++=HexDigits[*BinaryBuffer & 0x0F];
BinaryBuffer++;
CurrentLength-= 2;
}
*HexBuffer= 0;
return (HexBuffer - Start);
}
SQLRETURN MADB_DaeStmt(MADB_Stmt *Stmt, SQLUSMALLINT Operation)
{
char *TableName= MADB_GetTableName(Stmt);
char *CatalogName= MADB_GetCatalogName(Stmt);
MADB_DynString DynStmt;
MADB_CLEAR_ERROR(&Stmt->Error);
memset(&DynStmt, 0, sizeof(MADB_DynString));
if (Stmt->DaeStmt)
Stmt->Methods->StmtFree(Stmt->DaeStmt, SQL_DROP);
Stmt->DaeStmt= NULL;
if (!SQL_SUCCEEDED(MA_SQLAllocHandle(SQL_HANDLE_STMT, (SQLHANDLE)Stmt->Connection, (SQLHANDLE *)&Stmt->DaeStmt)))
{
MADB_CopyError(&Stmt->Error, &Stmt->Connection->Error);
goto end;
}
switch(Operation)
{
case SQL_ADD:
if (MADB_InitDynamicString(&DynStmt, "INSERT INTO ", 1024, 1024) ||
MADB_DynStrAppendQuoted(&DynStmt, CatalogName) ||
MADB_DynstrAppend(&DynStmt, ".") ||
MADB_DynStrAppendQuoted(&DynStmt, TableName)||
MADB_DynStrUpdateSet(Stmt, &DynStmt))
{
MADB_DynstrFree(&DynStmt);
return Stmt->Error.ReturnValue;
}
Stmt->DataExecutionType= MADB_DAE_ADD;
break;
case SQL_DELETE:
if (MADB_InitDynamicString(&DynStmt, "DELETE FROM ", 1024, 1024) ||
MADB_DynStrAppendQuoted(&DynStmt, CatalogName) ||
MADB_DynstrAppend(&DynStmt, ".") ||
MADB_DynStrAppendQuoted(&DynStmt, TableName) ||
MADB_DynStrGetWhere(Stmt, &DynStmt, TableName, FALSE))
{
MADB_DynstrFree(&DynStmt);
return Stmt->Error.ReturnValue;
}
Stmt->DataExecutionType= MADB_DAE_DELETE;
break;
case SQL_UPDATE:
if (MADB_InitDynamicString(&DynStmt, "UPDATE ", 1024, 1024) ||
MADB_DynStrAppendQuoted(&DynStmt, CatalogName) ||
MADB_DynstrAppend(&DynStmt, ".") ||
MADB_DynStrAppendQuoted(&DynStmt, TableName)||
MADB_DynStrUpdateSet(Stmt, &DynStmt)||
MADB_DynStrGetWhere(Stmt, &DynStmt, TableName, FALSE))
{
MADB_DynstrFree(&DynStmt);
return Stmt->Error.ReturnValue;
}
Stmt->DataExecutionType= MADB_DAE_UPDATE;
break;
}
if (!SQL_SUCCEEDED(Stmt->DaeStmt->Methods->Prepare(Stmt->DaeStmt, DynStmt.str, SQL_NTS, FALSE)))
{
MADB_CopyError(&Stmt->Error, &Stmt->DaeStmt->Error);
Stmt->Methods->StmtFree(Stmt->DaeStmt, SQL_DROP);
}
end:
MADB_DynstrFree(&DynStmt);
return Stmt->Error.ReturnValue;
}
int MADB_FindNextDaeParam(MADB_Desc *Desc, int InitialParam, SQLSMALLINT RowNumber)
{
int i;
MADB_DescRecord *Record;
for (i= InitialParam > -1 ? InitialParam + 1 : 0; i < Desc->Header.Count; i++)
{
if ((Record= MADB_DescGetInternalRecord(Desc, i, MADB_DESC_READ)))
{
if (Record->OctetLengthPtr)
{
/* Stmt->DaeRowNumber is 1 based */
SQLLEN *OctetLength = (SQLLEN *)GetBindOffset(Desc, Record, Record->OctetLengthPtr, RowNumber > 1 ? RowNumber - 1 : 0, sizeof(SQLLEN));
if (PARAM_IS_DAE(OctetLength))
{
return i;
}
}
}
}
return MADB_NOPARAM;
}
BOOL MADB_IsNumericType(SQLSMALLINT ConciseType)
{
switch (ConciseType)
{
case SQL_C_DOUBLE:
case SQL_C_FLOAT:
case SQL_DECIMAL:
return TRUE;
}
return MADB_IsIntType(ConciseType);
}
BOOL MADB_IsIntType(SQLSMALLINT ConciseType)
{
switch (ConciseType)
{
case SQL_C_TINYINT:
case SQL_C_STINYINT:
case SQL_C_UTINYINT:
case SQL_C_SHORT:
case SQL_C_SSHORT:
case SQL_C_USHORT:
case SQL_C_LONG:
case SQL_C_SLONG:
case SQL_C_ULONG:
case SQL_C_UBIGINT:
case SQL_C_SBIGINT:
case SQL_BIGINT:
return TRUE;
}
return FALSE;
}
/* Now it's more like installing result */
void MADB_InstallStmt(MADB_Stmt *Stmt, MYSQL_STMT *stmt)
{
Stmt->stmt= stmt;
if (mysql_stmt_field_count(Stmt->stmt) == 0)
{
MADB_DescFree(Stmt->Ird, TRUE);
Stmt->AffectedRows= mysql_stmt_affected_rows(Stmt->stmt);
}
else
{
Stmt->AffectedRows= 0;
MADB_StmtResetResultStructures(Stmt);
MADB_DescSetIrdMetadata(Stmt, mysql_fetch_fields(FetchMetadata(Stmt)), mysql_stmt_field_count(Stmt->stmt));
}
}

Comment ( 0 )

Sign in for post a comment