1 Star 0 Fork 53

zhangtingtingting/openGauss-connector-odbc

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
parse.c 53.80 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292
/*--------
* Module: parse.c
*
* Description: This module contains routines related to parsing SQL
* statements. This can be useful for two reasons:
*
* 1. So the query does not actually have to be executed
* to return data about it
*
* 2. To be able to return information about precision,
* nullability, aliases, etc. in the functions
* SQLDescribeCol and SQLColAttributes. Currently,
* Postgres doesn't return any information about
* these things in a query.
*
* Classes: none
*
* API functions: none
*
* Comments: See "readme.txt" for copyright and license information.
*--------
*/
/* Multibyte support Eiji Tokuya 2001-03-15 */
#include "psqlodbc.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "statement.h"
#include "connection.h"
#include "qresult.h"
#include "pgtypes.h"
#include "pgapifunc.h"
#include "catfunc.h"
#include "multibyte.h"
#include "misc.h"
#define FLD_INCR 32
#define TAB_INCR 8
#define COLI_INCR 16
#define COLI_RECYCLE 128
static const char *getNextToken(int ccsc, char escape_in_literal, const char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric);
static void getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k);
static char searchColInfo(COL_INFO *col_info, FIELD_INFO *fi);
static BOOL getColumnsInfo(ConnectionClass *, TABLE_INFO *, OID, StatementClass *);
Int4 FI_precision(const FIELD_INFO *fi)
{
OID ftype;
if (!fi) return -1;
ftype = FI_type(fi);
switch (ftype)
{
case PG_TYPE_NUMERIC:
return fi->column_size;
case PG_TYPE_DATETIME:
case PG_TYPE_TIMESTAMP_NO_TMZONE:
return fi->decimal_digits;
}
return 0;
}
Int4 FI_scale(const FIELD_INFO *fi)
{
OID ftype;
if (!fi) return -1;
ftype = FI_type(fi);
switch (ftype)
{
case PG_TYPE_NUMERIC:
return fi->decimal_digits;
}
return 0;
}
static const char *
getNextToken(
int ccsc, /* client encoding */
char escape_ch,
const char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric)
{
size_t out = 0;
size_t taglen;
char in_quote, in_dollar_quote, in_escape;
const UCHAR *tag, *tagend;
encoded_str encstr;
char escape_in_literal;
const UCHAR *tstr = (const UCHAR *) s;
UCHAR tchar, qc;
if (smax <= 1)
return NULL;
smax--;
/* skip leading delimiters */
while (isspace(*tstr) || *tstr == ',')
{
tstr++;
}
if (*tstr == '\0')
{
token[0] = '\0';
return NULL;
}
if (quote)
*quote = FALSE;
if (dquote)
*dquote = FALSE;
if (numeric)
*numeric = FALSE;
encoded_str_constr(&encstr, ccsc, (const char *) tstr);
/* get the next token */
for (tchar = encoded_nextchar(&encstr); tchar && out < smax; tstr++, tchar = encoded_nextchar(&encstr))
{
if (MBCS_NON_ASCII(encstr))
{
token[out++] = tchar;
continue;
}
if (isspace(tchar) || tchar == ',')
break;
/* Handle quoted stuff */
in_quote = in_dollar_quote = FALSE;
taglen = 0;
tag = NULL;
escape_in_literal = '\0';
if (out == 0)
{
qc = tchar;
if (qc == DOLLAR_QUOTE)
{
in_quote = in_dollar_quote = TRUE;
tag = tstr;
taglen = 1;
if (tagend = (const UCHAR *) strchr((const char *) tstr + 1, DOLLAR_QUOTE), NULL != tagend)
taglen = tagend - tstr + 1;
tstr += (taglen - 1);
encoded_position_shift(&encstr, taglen - 1);
if (quote)
*quote = TRUE;
}
else if (qc == LITERAL_QUOTE)
{
in_quote = TRUE;
if (quote)
*quote = TRUE;
escape_in_literal = escape_ch;
if (!escape_in_literal)
{
if (LITERAL_EXT == tstr[-1])
escape_in_literal = ESCAPE_IN_LITERAL;
}
}
else if (qc == IDENTIFIER_QUOTE)
{
in_quote = TRUE;
if (dquote)
*dquote = TRUE;
}
} /* out == 0 */
if (in_quote) /* dquote, dollar_quote */
{
in_escape = FALSE;
for (tstr++, tchar = encoded_nextchar(&encstr); tchar != '\0' && out != smax; tstr++, tchar = encoded_nextchar(&encstr))
{
if (MBCS_NON_ASCII(encstr))
{
token[out++] = tchar;
continue;
}
if (in_escape)
in_escape = FALSE;
else if (tchar == qc)
{
if (!in_dollar_quote)
{
/*
* Peek at the next byte to see if this is a '' or
* "", i.e a quote character that has been escaped
* by doubling it.
*/
if (tstr[1] == qc)
{
tstr++;
tchar = encoded_nextchar(&encstr);
}
else
break;
}
else if (strncmp((const char *) tstr, (const char *) tag, taglen) == 0)
{
tstr += (taglen - 1);
tchar = encoded_position_shift(&encstr, taglen - 1);
break;
}
token[out++] = tchar;
}
else if (LITERAL_QUOTE == qc && tchar == escape_in_literal)
{
in_escape = TRUE;
}
else
{
token[out++] = tchar;
}
} /* for */
if (tchar == qc)
tstr++;
break;
} /* in_quote */
/* Check for numeric literals */
if (out == 0 && isdigit(tchar))
{
if (numeric)
*numeric = TRUE;
token[out++] = tchar;
tstr++;
while ((isalnum(*tstr) || *tstr == '.') && out < smax)
{
token[out++] = *tstr;
tstr++;
}
break;
}
if (ispunct(tchar) && tchar != '_')
{
MYLOG(0, "got ispunct: s[] = '%c'\n", tchar);
if (out == 0)
{
token[out++] = tchar;
tstr++;
}
break;
}
if (out < smax)
token[out++] = tchar;
} /* for */
token[out] = '\0';
/* find the delimiter */
while (isspace(*tstr))
tstr++;
/* return the most priority delimiter */
if (*tstr == ',')
{
if (delim)
*delim = *tstr;
}
else if (*tstr == '\0')
{
if (delim)
*delim = '\0';
}
else
{
if (delim)
*delim = ' ';
}
/* skip trailing blanks */
while (isspace(*tstr))
tstr++;
return (const char *) tstr;
}
static void
getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k)
{
char *str;
MYLOG(DETAIL_LOG_LEVEL, "entering non-manual result\n");
fi->dquote = TRUE;
STR_TO_NAME(fi->column_name, QR_get_value_backend_text(col_info->result, k, COLUMNS_COLUMN_NAME));
fi->columntype = (OID) QR_get_value_backend_int(col_info->result, k, COLUMNS_FIELD_TYPE, NULL);
fi->column_size = QR_get_value_backend_int(col_info->result, k, COLUMNS_PRECISION, NULL);
fi->length = QR_get_value_backend_int(col_info->result, k, COLUMNS_LENGTH, NULL);
if (str = QR_get_value_backend_text(col_info->result, k, COLUMNS_SCALE), str)
fi->decimal_digits = atoi(str);
else
fi->decimal_digits = -1;
fi->nullable = QR_get_value_backend_int(col_info->result, k, COLUMNS_NULLABLE, NULL);
fi->display_size = QR_get_value_backend_int(col_info->result, k, COLUMNS_DISPLAY_SIZE, NULL);
fi->auto_increment = QR_get_value_backend_int(col_info->result, k, COLUMNS_AUTO_INCREMENT, NULL);
}
static char
searchColInfo(COL_INFO *col_info, FIELD_INFO *fi)
{
int k,
cmp, attnum, atttypmod;
OID basetype;
const char *col;
MYLOG(DETAIL_LOG_LEVEL, "entering num_cols=" FORMAT_ULEN " col=%s\n", QR_get_num_cached_tuples(col_info->result), PRINT_NAME(fi->column_name));
if (fi->attnum < 0)
return FALSE;
for (k = 0; k < QR_get_num_cached_tuples(col_info->result); k++)
{
if (fi->attnum > 0)
{
attnum = QR_get_value_backend_int(col_info->result, k, COLUMNS_PHYSICAL_NUMBER, NULL);
if (basetype = (OID) strtoul(QR_get_value_backend_text(col_info->result, k, COLUMNS_BASE_TYPEID), NULL, 10), 0 == basetype)
basetype = (OID) strtoul(QR_get_value_backend_text(col_info->result, k, COLUMNS_FIELD_TYPE), NULL, 10);
atttypmod = QR_get_value_backend_int(col_info->result, k, COLUMNS_ATTTYPMOD, NULL);
MYLOG(DETAIL_LOG_LEVEL, "%d attnum=%d\n", k, attnum);
if (attnum == fi->attnum &&
basetype == fi->basetype &&
atttypmod == fi->typmod)
{
getColInfo(col_info, fi, k);
MYLOG(0, "PARSE: searchColInfo by attnum=%d\n", attnum);
return TRUE;
}
}
else if (NAME_IS_VALID(fi->column_name))
{
col = QR_get_value_backend_text(col_info->result, k, COLUMNS_COLUMN_NAME);
MYLOG(DETAIL_LOG_LEVEL, "%d col=%s\n", k, col);
if (fi->dquote)
cmp = strcmp(col, GET_NAME(fi->column_name));
else
cmp = stricmp(col, GET_NAME(fi->column_name));
if (!cmp)
{
if (!fi->dquote)
STR_TO_NAME(fi->column_name, col);
getColInfo(col_info, fi, k);
MYLOG(0, "PARSE: \n");
return TRUE;
}
}
}
return FALSE;
}
/*
* lower the unquoted name
*/
static
void lower_the_name(char *name, ConnectionClass *conn, BOOL dquote)
{
if (!dquote)
{
char *ptr;
encoded_str encstr;
make_encoded_str(&encstr, conn, name);
/* lower case table name */
for (ptr = name; *ptr; ptr++)
{
encoded_nextchar(&encstr);
if (!MBCS_NON_ASCII(encstr))
*ptr = tolower((UCHAR) *ptr);
}
}
}
static BOOL CheckHasOidsUsingSaved(StatementClass *stmt, TABLE_INFO *ti)
{
const COL_INFO *coli;
int table_info;
BOOL hasoids = FALSE, hassubclass =FALSE, keyFound = FALSE;
MYLOG(DETAIL_LOG_LEVEL, "ti->col_info=%p\n", ti->col_info);
if (TI_checked_hasoids(ti))
;
else if (coli = ti->col_info, NULL != coli)
{
table_info = coli->table_info;
if (0 == (table_info & TBINFO_HASSUBCLASS))
{
TI_set_has_no_subclass(ti);
}
else
{
hassubclass = TRUE;
TI_set_hassubclass(ti);
STR_TO_NAME(ti->bestitem, TABLEOID_NAME);
STRX_TO_NAME(ti->bestqual, "\"" TABLEOID_NAME "\" = %u");
}
if (!hassubclass)
{
if (0 == (table_info & TBINFO_HASOIDS))
{
TI_set_has_no_oids(ti);
}
else
{
hasoids = TRUE;
TI_set_hasoids(ti);
STR_TO_NAME(ti->bestitem, OID_NAME);
STRX_TO_NAME(ti->bestqual, "\"" OID_NAME "\" = %u");
}
}
ti->table_oid = coli->table_oid;
if (!hasoids && !hassubclass)
{
QResultClass *res = coli->result;
int num_tuples = res ? QR_get_num_cached_tuples(res) : -1;
if (num_tuples > 0)
{
int i;
for (i = 0; i < num_tuples; i++)
{
if (QR_get_value_backend_int(res, i, COLUMNS_AUTO_INCREMENT, NULL) != 0&&
QR_get_value_backend_int(res, i, COLUMNS_FIELD_TYPE, NULL) == PG_TYPE_INT4)
{
char query[512];
STR_TO_NAME(ti->bestitem, QR_get_value_backend_text(res, i, COLUMNS_COLUMN_NAME));
SPRINTF_FIXED(query, "\"%s\" = %%d", SAFE_NAME(ti->bestitem));
STRX_TO_NAME(ti->bestqual, query);
break;
}
}
}
}
TI_set_hasoids_checked(ti);
}
else
return FALSE;
stmt->num_key_fields = PG_NUM_NORMAL_KEYS;
if (TI_has_subclass(ti))
keyFound = FALSE;
else if (TI_has_oids(ti))
keyFound = TRUE;
else if (NAME_IS_NULL(ti->bestqual))
{
keyFound = TRUE;
stmt->num_key_fields--;
}
else
keyFound = TRUE;
MYLOG(DETAIL_LOG_LEVEL, "subclass=%d oids=%d bestqual=%s keyFound=%d num_key_fields=%d\n", TI_has_subclass(ti), TI_has_oids(ti), PRINT_NAME(ti->bestqual), keyFound, stmt->num_key_fields);
SC_set_checked_hasoids(stmt, keyFound);
return TRUE;
}
static BOOL CheckHasOids(StatementClass * stmt)
{
QResultClass *res;
BOOL hasoids = TRUE, hassubclass =FALSE, foundKey = FALSE;
char query[512];
ConnectionClass *conn = SC_get_conn(stmt);
TABLE_INFO *ti;
MYLOG(0, "Entering\n");
if (0 != SC_checked_hasoids(stmt))
return TRUE;
if (!stmt->ti || !stmt->ti[0])
return FALSE;
ti = stmt->ti[0];
if (CheckHasOidsUsingSaved(stmt, ti))
return TRUE;
// no longer come here??
SPRINTF_FIXED(query,
"select relhasoids, c.oid, relhassubclass from pg_class c, pg_namespace n where relname = '%s' and nspname = '%s' and c.relnamespace = n.oid",
SAFE_NAME(ti->table_name), SAFE_NAME(ti->schema_name));
res = CC_send_query(conn, query, NULL, READ_ONLY_QUERY, NULL);
if (QR_command_maybe_successful(res))
{
stmt->num_key_fields = PG_NUM_NORMAL_KEYS;
if (1 == QR_get_num_total_tuples(res))
{
const char *value = QR_get_value_backend_text(res, 0, 0);
const char *value2 = QR_get_value_backend_text(res, 0, 2);
if (value && ('f' == *value || '0' == *value))
{
hasoids = FALSE;
TI_set_has_no_oids(ti);
}
else
{
TI_set_hasoids(ti);
foundKey = TRUE;
STR_TO_NAME(ti->bestitem, OID_NAME);
STRX_TO_NAME(ti->bestqual, "\"" OID_NAME "\" = %u");
}
if (value2 && ('f' == *value2 || '0' == *value2))
{
TI_set_has_no_subclass(ti);
}
else
{
hassubclass = TRUE;
TI_set_hassubclass(ti);
STR_TO_NAME(ti->bestitem, TABLEOID_NAME);
STRX_TO_NAME(ti->bestqual, "\"" TABLEOID_NAME "\" = %u");
}
TI_set_hasoids_checked(ti);
ti->table_oid = (OID) strtoul(QR_get_value_backend_text(res, 0, 1), NULL, 10);
}
QR_Destructor(res);
res = NULL;
if (!hasoids && !hassubclass)
{
SPRINTF_FIXED(query, "select a.attname, a.atttypid from pg_index i, pg_attribute a where indrelid=%u and indnatts=1 and indisunique and indexprs is null and indpred is null and i.indrelid = a.attrelid and a.attnum=i.indkey[0] and attnotnull and atttypid in (%d, %d)", ti->table_oid, PG_TYPE_INT4, PG_TYPE_OID);
res = CC_send_query(conn, query, NULL, READ_ONLY_QUERY, NULL);
if (QR_command_maybe_successful(res) && QR_get_num_total_tuples(res) > 0)
{
foundKey = TRUE;
STR_TO_NAME(ti->bestitem, QR_get_value_backend_text(res, 0, 0));
SPRINTF_FIXED(query, "\"%s\" = %%", SAFE_NAME(ti->bestitem));
if (PG_TYPE_INT4 == (OID) QR_get_value_backend_int(res, 0, 1, NULL))
STRCAT_FIXED(query, "d");
else
STRCAT_FIXED(query, "u");
STRX_TO_NAME(ti->bestqual, query);
}
else
{
/* stmt->updatable = FALSE; */
foundKey = TRUE;
stmt->num_key_fields--;
}
}
}
QR_Destructor(res);
SC_set_checked_hasoids(stmt, foundKey);
MYLOG(DETAIL_LOG_LEVEL, "subclass=%d oids=%d bestqual=%s foundKey=%d num_key_fields=%d\n", TI_has_subclass(ti), TI_has_oids(ti), PRINT_NAME(ti->bestqual), foundKey, stmt->num_key_fields);
return TRUE;
}
static BOOL increaseNtab(StatementClass *stmt, const char *func)
{
TABLE_INFO **ti = stmt->ti, *wti;
if (!(stmt->ntab % TAB_INCR))
{
SC_REALLOC_return_with_error(ti, TABLE_INFO *, (stmt->ntab + TAB_INCR) * sizeof(TABLE_INFO *), stmt, "PGAPI_AllocStmt failed in parse_statement for TABLE_INFO", FALSE);
stmt->ti = ti;
}
wti = ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO));
if (wti == NULL)
{
SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for TABLE_INFO(2).", func);
return FALSE;
}
TI_Constructor(wti, SC_get_conn(stmt));
stmt->ntab++;
return TRUE;
}
static void setNumFields(IRDFields *irdflds, size_t numFields)
{
FIELD_INFO **fi = irdflds->fi;
size_t nfields = irdflds->nfields;
if (numFields < nfields)
{
int i;
for (i = (int) numFields; i < (int) nfields; i++)
{
if (fi[i])
fi[i]->flag = 0;
}
}
irdflds->nfields = (UInt4) numFields;
}
void SC_initialize_cols_info(StatementClass *stmt, BOOL DCdestroy, BOOL parseReset)
{
IRDFields *irdflds = SC_get_IRDF(stmt);
/* Free the parsed table information */
if (stmt->ti)
{
TI_Destructor(stmt->ti, stmt->ntab);
free(stmt->ti);
stmt->ti = NULL;
}
stmt->ntab = 0;
if (DCdestroy) /* Free the parsed field information */
DC_Destructor((DescriptorClass *) SC_get_IRD(stmt));
else
setNumFields(irdflds, 0);
if (parseReset)
{
stmt->parse_status = STMT_PARSE_NONE;
SC_reset_updatable(stmt);
}
}
static BOOL allocateFields(IRDFields *irdflds, size_t sizeRequested)
{
FIELD_INFO **fi = irdflds->fi;
size_t alloc_size, incr_size;
if (sizeRequested <= irdflds->allocated)
return TRUE;
alloc_size = (0 != irdflds->allocated ? irdflds->allocated : FLD_INCR);
for (; alloc_size < sizeRequested; alloc_size *= 2)
;
incr_size = sizeof(FIELD_INFO *) * (alloc_size - irdflds->allocated);
fi = (FIELD_INFO **) realloc(fi, alloc_size * sizeof(FIELD_INFO *));
if (!fi)
{
irdflds->fi = NULL;
irdflds->allocated = irdflds->nfields = 0;
return FALSE;
}
memset(&fi[irdflds->allocated], 0, incr_size);
irdflds->fi = fi;
irdflds->allocated = (SQLSMALLINT) alloc_size;
return TRUE;
}
/*
* This function may not be called but when it is called ...
*/
static void xxxxx(StatementClass *stmt, FIELD_INFO *fi, QResultClass *res, int i)
{
STR_TO_NAME(fi->column_alias, QR_get_fieldname(res, i));
fi->basetype = QR_get_field_type(res, i);
if (0 == fi->columntype)
fi->columntype = fi->basetype;
if (fi->attnum < 0)
{
fi->nullable = FALSE;
fi->updatable = FALSE;
}
else if (fi->attnum > 0)
{
int unknowns_as = 0;
int type = pg_true_type(SC_get_conn(stmt), fi->columntype, fi->basetype);
fi->nullable = TRUE; /* probably ? */
fi->column_size = pgtype_column_size(stmt, type, i, unknowns_as);
fi->length = pgtype_buffer_length(stmt, type, i, unknowns_as);
fi->decimal_digits = pgtype_decimal_digits(stmt, type, i);
fi->display_size = pgtype_display_size(stmt, type, i, unknowns_as);
}
if (NAME_IS_NULL(fi->column_name))
{
switch (fi->attnum)
{
case CTID_ATTNUM:
STR_TO_NAME(fi->column_name, "ctid");
break;
case OID_ATTNUM:
STR_TO_NAME(fi->column_name, OID_NAME);
break;
case XMIN_ATTNUM:
STR_TO_NAME(fi->column_name, XMIN_NAME);
break;
}
}
}
static BOOL has_multi_table(const StatementClass *stmt)
{
BOOL multi_table = FALSE;
QResultClass *res;
MYLOG(DETAIL_LOG_LEVEL, "entering ntab=%d", stmt->ntab);
if (1 < stmt->ntab)
multi_table = TRUE;
else if (SC_has_join(stmt))
multi_table = TRUE;
else if (res = SC_get_Curres(stmt), NULL != res)
{
int i, num_fields = QR_NumPublicResultCols(res);
OID reloid = 0, greloid;
for (i = 0; i < num_fields; i++)
{
greloid = QR_get_relid(res, i);
if (0 != greloid)
{
if (0 == reloid)
reloid = greloid;
else if (reloid != greloid)
{
MYPRINTF(DETAIL_LOG_LEVEL, " DOHHH i=%d %u!=%u ", i, reloid, greloid);
multi_table = TRUE;
break;
}
}
}
}
MYPRINTF(DETAIL_LOG_LEVEL, " multi=%d\n", multi_table);
return multi_table;
}
/*
* SQLColAttribute tries to set the FIELD_INFO (using protocol 3).
*/
static BOOL
ColAttSet(StatementClass *stmt, TABLE_INFO *rti)
{
CSTR func = "ColAttSet";
QResultClass *res = SC_get_Curres(stmt);
IRDFields *irdflds = SC_get_IRDF(stmt);
COL_INFO *col_info = NULL;
FIELD_INFO **fi, *wfi;
OID reloid = 0;
Int2 attid;
int i, num_fields;
BOOL fi_reuse, updatable, call_xxxxx;
MYLOG(0, "entering\n");
if (reloid = rti->table_oid, 0 == reloid)
return FALSE;
if (0 != (rti->flags & TI_COLATTRIBUTE))
return TRUE;
col_info = rti->col_info;
if (!QR_command_maybe_successful(res))
return FALSE;
if (num_fields = QR_NumPublicResultCols(res), num_fields <= 0)
return FALSE;
fi = irdflds->fi;
if (num_fields > (int) irdflds->allocated)
{
if (!allocateFields(irdflds, num_fields))
return FALSE;
fi = irdflds->fi;
}
setNumFields(irdflds, num_fields);
updatable = TI_is_updatable(rti);
MYLOG(0, "updatable=%d tab=%d fields=%d", updatable, stmt->ntab, num_fields);
if (updatable)
{
if (1 > stmt->ntab)
updatable = FALSE;
else if (has_multi_table(stmt))
updatable = FALSE;
}
MYPRINTF(0, "->%d\n", updatable);
if (stmt->updatable < 0)
SC_set_updatable(stmt, updatable);
for (i = 0; i < num_fields; i++)
{
if (reloid == (OID) QR_get_relid(res, i))
{
if (wfi = fi[i], NULL == wfi)
{
wfi = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
if (wfi == NULL)
{
SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for field info.", func);
return FALSE;
}
fi_reuse = FALSE;
fi[i] = wfi;
}
else if (FI_is_applicable(wfi))
continue;
else
fi_reuse = TRUE;
FI_Constructor(wfi, fi_reuse);
attid = (Int2) QR_get_attid(res, i);
wfi->attnum = attid;
wfi->basetype = QR_get_field_type(res, i);
wfi->typmod = QR_get_atttypmod(res, i);
call_xxxxx = TRUE;
if (searchColInfo(col_info, wfi))
{
STR_TO_NAME(wfi->column_alias, QR_get_fieldname(res, i));
wfi->basetype = QR_get_field_type(res, i);
wfi->updatable = updatable;
call_xxxxx = FALSE;
}
else
{
if (attid > 0)
{
if (getColumnsInfo(NULL, rti, reloid, stmt) &&
searchColInfo(col_info, wfi))
{
STR_TO_NAME(wfi->column_alias, QR_get_fieldname(res, i));
wfi->basetype = QR_get_field_type(res, i);
wfi->updatable = updatable;
call_xxxxx= FALSE;
}
}
}
if (call_xxxxx)
xxxxx(stmt, wfi, res, i);
wfi->ti = rti;
wfi->flag |= FIELD_COL_ATTRIBUTE;
}
}
rti->flags |= TI_COLATTRIBUTE;
return TRUE;
}
static BOOL
getCOLIfromTable(ConnectionClass *conn, pgNAME *schema_name, pgNAME table_name,
COL_INFO **coli)
{
int colidx;
BOOL found = FALSE;
*coli = NULL;
if (NAME_IS_NULL(table_name))
return TRUE;
if (NAME_IS_NULL(*schema_name))
{
const char *curschema = CC_get_current_schema(conn);
/*
* Though current_schema() doesn't have
* much sense in PostgreSQL, we first
* check the current_schema() when no
* explicit schema name is specified.
*/
if (curschema)
{
for (colidx = 0; colidx < conn->ntables; colidx++)
{
if (!NAMEICMP(conn->col_info[colidx]->table_name, table_name) &&
!stricmp(SAFE_NAME(conn->col_info[colidx]->schema_name), curschema))
{
MYLOG(0, "FOUND col_info table='%s' current schema='%s'\n", PRINT_NAME(table_name), curschema);
found = TRUE;
STR_TO_NAME(*schema_name, curschema);
break;
}
}
}
if (!found)
{
QResultClass *res;
char token[256], relcnv[128];
BOOL tblFound = FALSE;
/*
* We also have to check as follows.
*/
SPRINTF_FIXED(token,
"select nspname from pg_namespace n, pg_class c"
" where c.relnamespace=n.oid and c.oid='%s'::regclass",
identifierEscape((const SQLCHAR *) SAFE_NAME(table_name), SQL_NTS, conn, relcnv, sizeof(relcnv), TRUE));
res = CC_send_query(conn, token, NULL, READ_ONLY_QUERY, NULL);
if (QR_command_maybe_successful(res))
{
if (QR_get_num_total_tuples(res) == 1)
{
tblFound = TRUE;
STR_TO_NAME(*schema_name, QR_get_value_backend_text(res, 0, 0));
}
}
QR_Destructor(res);
if (!tblFound)
return FALSE;
}
}
if (!found && NAME_IS_VALID(*schema_name))
{
for (colidx = 0; colidx < conn->ntables; colidx++)
{
if (!NAMEICMP(conn->col_info[colidx]->table_name, table_name) &&
!NAMEICMP(conn->col_info[colidx]->schema_name, *schema_name))
{
MYLOG(0, "FOUND col_info table='%s' schema='%s'\n", PRINT_NAME(table_name), PRINT_NAME(*schema_name));
found = TRUE;
break;
}
}
}
*coli = found ? conn->col_info[colidx] : NULL;
return TRUE; /* success */
}
static BOOL
getColumnsInfo(ConnectionClass *conn, TABLE_INFO *wti, OID greloid, StatementClass *stmt)
{
BOOL found = FALSE;
RETCODE result;
HSTMT hcol_stmt = NULL;
StatementClass *col_stmt;
QResultClass *res;
MYLOG(0, "entering Getting PG_Columns for table %u(%s)\n", greloid, PRINT_NAME(wti->table_name));
if (NULL == conn)
conn = SC_get_conn(stmt);
result = PGAPI_AllocStmt(conn, &hcol_stmt, 0);
if (!SQL_SUCCEEDED(result))
{
if (stmt)
SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for columns.", __FUNCTION__);
goto cleanup;
}
col_stmt = (StatementClass *) hcol_stmt;
if (greloid)
result = PGAPI_Columns(hcol_stmt, NULL, 0,
NULL, 0, NULL, 0, NULL, 0,
PODBC_SEARCH_BY_IDS, greloid, 0);
else
result = PGAPI_Columns(hcol_stmt, NULL, 0,
(SQLCHAR *) SAFE_NAME(wti->schema_name), SQL_NTS,
(SQLCHAR *) SAFE_NAME(wti->table_name), SQL_NTS,
NULL, 0,
PODBC_NOT_SEARCH_PATTERN, 0, 0);
MYLOG(0, " Past PG_Columns\n");
res = SC_get_Curres(col_stmt);
if (SQL_SUCCEEDED(result)
&& res != NULL && QR_get_num_cached_tuples(res) > 0)
{
BOOL coli_exist = FALSE;
COL_INFO *coli = NULL, *ccoli = NULL, *tcoli;
int k;
time_t acctime = 0;
MYLOG(0, " Success\n");
if (greloid != 0)
{
for (k = 0; k < conn->ntables; k++)
{
tcoli = conn->col_info[k];
if (tcoli->table_oid == greloid)
{
coli = tcoli;
coli_exist = TRUE;
break;
}
}
}
if (!coli_exist)
{
for (k = 0; k < conn->ntables; k++)
{
tcoli = conn->col_info[k];
if (0 < tcoli->refcnt)
continue;
if ((0 == tcoli->table_oid &&
NAME_IS_NULL(tcoli->table_name)) ||
strnicmp(SAFE_NAME(tcoli->schema_name), "pg_temp_", 8) == 0)
{
coli = tcoli;
coli_exist = TRUE;
break;
}
if (NULL == ccoli ||
tcoli->acc_time < acctime)
{
ccoli = tcoli;
acctime = tcoli->acc_time;
}
}
if (!coli_exist &&
NULL != ccoli &&
conn->ntables >= COLI_RECYCLE)
{
coli_exist = TRUE;
coli = ccoli;
}
}
if (coli_exist)
{
free_col_info_contents(coli);
}
else
{
if (conn->ntables >= conn->coli_allocated)
{
Int2 new_alloc;
COL_INFO **col_info;
new_alloc = conn->coli_allocated * 2;
if (new_alloc <= conn->ntables)
new_alloc = COLI_INCR;
MYLOG(0, "PARSE: Allocating col_info at ntables=%d\n", conn->ntables);
col_info = (COL_INFO **) realloc(conn->col_info, new_alloc * sizeof(COL_INFO *));
if (!col_info)
{
if (stmt)
SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info.", __FUNCTION__);
goto cleanup;
}
conn->col_info = col_info;
conn->coli_allocated = new_alloc;
}
MYLOG(0, "PARSE: malloc at conn->col_info[%d]\n", conn->ntables);
coli = conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO));
}
if (!coli)
{
if (stmt)
SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info(2).", __FUNCTION__);
goto cleanup;
}
col_info_initialize(coli);
coli->result = res;
if (res && QR_get_num_cached_tuples(res) > 0)
{
int num_tuples = QR_get_num_cached_tuples(res);
int i;
if (!greloid)
greloid = (OID) strtoul(QR_get_value_backend_text(res, 0, COLUMNS_TABLE_OID), NULL, 10);
if (!wti->table_oid)
wti->table_oid = greloid;
if (NAME_IS_NULL(wti->schema_name))
STR_TO_NAME(wti->schema_name,
QR_get_value_backend_text(res, 0, COLUMNS_SCHEMA_NAME));
if (NAME_IS_NULL(wti->table_name))
STR_TO_NAME(wti->table_name,
QR_get_value_backend_text(res, 0, COLUMNS_TABLE_NAME));
for (i = 0; i < num_tuples; i++)
{
if (NULL != QR_get_value_backend_text(res, 0, COLUMNS_TABLE_INFO))
{
coli->table_info = QR_get_value_backend_int(res, 0, COLUMNS_TABLE_INFO, NULL);
break;
}
}
}
MYLOG(DETAIL_LOG_LEVEL, "#2 %p->table_name=%s(%u)\n", wti, PRINT_NAME(wti->table_name), wti->table_oid);
/*
* Store the table name and the SQLColumns result
* structure
*/
if (NAME_IS_VALID(wti->schema_name))
{
NAME_TO_NAME(coli->schema_name, wti->schema_name);
}
else
NULL_THE_NAME(coli->schema_name);
NAME_TO_NAME(coli->table_name, wti->table_name);
coli->table_oid = wti->table_oid;
/*
* The connection will now free the result structures, so
* make sure that the statement doesn't free it
*/
SC_init_Result(col_stmt);
if (!coli_exist)
conn->ntables++;
if (res && QR_get_num_cached_tuples(res) > 0)
MYLOG(DETAIL_LOG_LEVEL, "oid item == %s\n", (const char *) QR_get_value_backend_text(res, 0, 3));
MYLOG(0, "Created col_info table='%s', ntables=%d\n", PRINT_NAME(wti->table_name), conn->ntables);
/* Associate a table from the statement with a SQLColumn info */
found = TRUE;
coli->refcnt++;
wti->col_info = coli;
}
cleanup:
if (hcol_stmt)
PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
return found;
}
BOOL getCOLIfromTI(const char *func, ConnectionClass *conn, StatementClass *stmt, const OID reloid, TABLE_INFO **pti)
{
BOOL colatt = FALSE, found = FALSE;
OID greloid = reloid;
TABLE_INFO *wti = *pti;
COL_INFO *coli;
MYLOG(DETAIL_LOG_LEVEL, "entering reloid=%u ti=%p\n", reloid, wti);
if (!conn)
conn = SC_get_conn(stmt);
if (!wti) /* SQLColAttribute case */
{
int i;
if (0 == greloid)
return FALSE;
if (!stmt)
return FALSE;
colatt = TRUE;
for (i = 0; i < stmt->ntab; i++)
{
if (stmt->ti[i]->table_oid == greloid)
{
wti = stmt->ti[i];
break;
}
}
if (!wti)
{
MYLOG(DETAIL_LOG_LEVEL, "before increaseNtab\n");
if (!increaseNtab(stmt, func))
return FALSE;
wti = stmt->ti[stmt->ntab - 1];
wti->table_oid = greloid;
}
*pti = wti;
}
MYLOG(DETAIL_LOG_LEVEL, "fi=%p greloid=%d col_info=%p\n", wti, greloid, wti->col_info);
if (0 == greloid)
greloid = wti->table_oid;
if (NULL != wti->col_info)
{
found = TRUE;
goto cleanup;
}
if (greloid != 0)
{
int colidx;
for (colidx = 0; colidx < conn->ntables; colidx++)
{
if (conn->col_info[colidx]->table_oid == greloid)
{
MYLOG(0, "FOUND col_info table=%ul\n", greloid);
found = TRUE;
wti->col_info = conn->col_info[colidx];
wti->col_info->refcnt++;
break;
}
}
}
else
{
if (!getCOLIfromTable(conn, &wti->schema_name, wti->table_name, &coli))
{
if (stmt)
{
SC_set_parse_status(stmt, STMT_PARSE_FATAL);
SC_set_error(stmt, STMT_EXEC_ERROR, "Table not found", func);
SC_reset_updatable(stmt);
}
return FALSE;
}
else if (NULL != coli)
{
found = TRUE;
coli->refcnt++;
wti->col_info = coli;
}
}
if (found)
goto cleanup;
else if (0 != greloid || NAME_IS_VALID(wti->table_name))
found = getColumnsInfo(conn, wti, greloid, stmt);
cleanup:
if (found)
{
QResultClass *res = wti->col_info->result;
if (res && QR_get_num_cached_tuples(res) > 0)
{
if (!greloid)
greloid = (OID) strtoul(QR_get_value_backend_text(res, 0, COLUMNS_TABLE_OID), NULL, 10);
if (!wti->table_oid)
wti->table_oid = greloid;
if (NAME_IS_NULL(wti->schema_name))
STR_TO_NAME(wti->schema_name,
QR_get_value_backend_text(res, 0, COLUMNS_SCHEMA_NAME));
if (NAME_IS_NULL(wti->table_name))
STR_TO_NAME(wti->table_name,
QR_get_value_backend_text(res, 0, COLUMNS_TABLE_NAME));
}
MYLOG(DETAIL_LOG_LEVEL, "#1 %p->table_name=%s(%u)\n", wti, PRINT_NAME(wti->table_name), wti->table_oid);
if (colatt /* SQLColAttribute case */
&& 0 == (wti->flags & TI_COLATTRIBUTE))
{
if (stmt)
ColAttSet(stmt, wti);
}
wti->col_info->acc_time = SC_get_time(stmt);
}
else if (!colatt && stmt)
SC_set_parse_status(stmt, STMT_PARSE_FATAL);
MYLOG(DETAIL_LOG_LEVEL, "leaving returns %d\n", found);
return found;
}
SQLRETURN
SC_set_SS_columnkey(StatementClass *stmt)
{
IRDFields *irdflds = SC_get_IRDF(stmt);
FIELD_INFO **fi = irdflds->fi, *tfi;
size_t nfields = irdflds->nfields;
HSTMT pstmt = NULL;
SQLRETURN ret = SQL_SUCCESS;
BOOL contains_key = FALSE;
int i;
MYLOG(DETAIL_LOG_LEVEL, "entering fields=" FORMAT_SIZE_T " ntab=%d\n", nfields, stmt->ntab);
if (!fi) return ret;
if (0 >= nfields) return ret;
if (!has_multi_table(stmt) && 1 == stmt->ntab)
{
TABLE_INFO **ti = stmt->ti, *oneti;
ConnectionClass *conn = SC_get_conn(stmt);
OID internal_asis_type = SQL_C_CHAR;
char keycolnam[MAX_INFO_STRING];
SQLLEN keycollen;
ret = PGAPI_AllocStmt(conn, &pstmt, 0);
if (!SQL_SUCCEEDED(ret))
return ret;
oneti = ti[0];
ret = PGAPI_PrimaryKeys(pstmt, NULL, 0, NULL, 0, NULL, 0, oneti->table_oid);
if (!SQL_SUCCEEDED(ret))
goto cleanup;
#ifdef UNICODE_SUPPORT
if (CC_is_in_unicode_driver(conn))
internal_asis_type = INTERNAL_ASIS_TYPE;
#endif /* UNICODE_SUPPORT */
ret = PGAPI_BindCol(pstmt, 4, internal_asis_type, keycolnam, MAX_INFO_STRING, &keycollen);
if (!SQL_SUCCEEDED(ret))
goto cleanup;
contains_key = TRUE;
ret = PGAPI_Fetch(pstmt);
while (SQL_SUCCEEDED(ret))
{
for (i = 0; i < nfields; i++)
{
if (tfi = fi[i], NULL == tfi)
continue;
if (!FI_is_applicable(tfi))
continue;
if (oneti == tfi->ti &&
strcmp(keycolnam, SAFE_NAME(tfi->column_name)) == 0)
{
MYLOG(DETAIL_LOG_LEVEL, "key %s found at %p\n", keycolnam, fi + i);
tfi->columnkey = TRUE;
break;
}
}
if (i >= nfields)
{
MYLOG(0, "%s not found\n", keycolnam);
break;
}
ret = PGAPI_Fetch(pstmt);
}
if (SQL_SUCCEEDED(ret))
contains_key = FALSE;
else if (SQL_NO_DATA_FOUND != ret)
goto cleanup;
ret = SQL_SUCCESS;
}
MYLOG(DETAIL_LOG_LEVEL, "contains_key=%d\n", contains_key);
for (i = 0; i < nfields; i++)
{
if (tfi = fi[i], NULL == tfi)
continue;
if (!FI_is_applicable(tfi))
continue;
if (!contains_key || tfi->columnkey < 0)
tfi->columnkey = FALSE;
}
cleanup:
if (pstmt)
PGAPI_FreeStmt(pstmt, SQL_DROP);
return ret;
}
static BOOL include_alias_wo_as(const char *token, const char *btoken)
{
MYLOG(0, "alias ? token=%s btoken=%s\n", token, btoken);
if ('\0' == btoken[0])
return FALSE;
else if (0 == stricmp(")", token))
return FALSE;
else if (0 == stricmp("as", btoken) ||
0 == stricmp("and", btoken) ||
0 == stricmp("or", btoken) ||
0 == stricmp("not", btoken) ||
0 == stricmp(",", btoken))
return FALSE;
else
{
CSTR ops = "+-*/%^|!@&#~<>=.";
const char *cptr, *optr;
for (cptr = btoken; *cptr; cptr++)
{
for (optr = ops; *optr; optr++)
{
if (*optr != *cptr)
return TRUE;
}
}
}
return FALSE;
}
static char *insert_as_to_the_statement(char *stmt, const char **pptr, const char **ptr)
{
size_t stsize = strlen(stmt), ppos = *pptr - stmt, remsize = stsize - ppos;
const int ins_size = 3;
char *newstmt = realloc(stmt, stsize + ins_size + 1);
if (newstmt)
{
char *sptr = newstmt + ppos;
memmove(sptr + ins_size, sptr, remsize + 1);
sptr[0] = 'a';
sptr[1] = 's';
sptr[2] = ' ';
*ptr = sptr + (*ptr - *pptr) + ins_size;
*pptr = sptr + ins_size;
}
return newstmt;
}
#define TOKEN_SIZE 256
static char
parse_the_statement(StatementClass *stmt, BOOL check_hasoids, BOOL sqlsvr_check)
{
CSTR func = "parse_the_statement";
char delimdsp[2], token[TOKEN_SIZE], stoken[TOKEN_SIZE], btoken[TOKEN_SIZE];
char delim,
quote,
dquote,
numeric,
unquoted;
const char *ptr;
const char *pptr = NULL;
char in_select = FALSE,
in_distinct = FALSE,
in_on = FALSE,
in_from = FALSE,
in_where = FALSE,
in_table = FALSE,
out_table = TRUE;
char in_field = FALSE,
in_expr = FALSE,
in_func = FALSE,
in_dot = FALSE,
in_as = FALSE;
int j,
i,
k = 0,
n,
blevel = 0, old_blevel, subqlevel = 0,
tbl_blevel = 0, allocated_size = -1, new_size,
nfields;
FIELD_INFO **fi, *wfi;
TABLE_INFO **ti, *wti;
char parse = FALSE, maybe_join = 0;
ConnectionClass *conn = SC_get_conn(stmt);
IRDFields *irdflds;
BOOL updatable = TRUE, column_has_alias = FALSE;
MYLOG(0, "entering...\n");
if (SC_parsed_status(stmt) != STMT_PARSE_NONE)
{
if (check_hasoids)
CheckHasOids(stmt);
return TRUE;
}
nfields = 0;
wfi = NULL;
wti = NULL;
ptr = stmt->statement;
if (sqlsvr_check)
{
irdflds = NULL;
fi = NULL;
ti = NULL;
}
else
{
SC_set_updatable(stmt, FALSE);
irdflds = SC_get_IRDF(stmt);
fi = irdflds->fi;
ti = stmt->ti;
allocated_size = irdflds->allocated;
SC_initialize_cols_info(stmt, FALSE, TRUE);
stmt->from_pos = -1;
stmt->where_pos = -1;
}
#define return DONT_CALL_RETURN_FROM_HERE???
delim = '\0';
token[0] = '\0';
while (pptr = (const char *) ptr, (delim != ',') ? STRCPY_FIXED(btoken, token) : (btoken[0] = '\0', 0), (ptr = getNextToken(conn->ccsc, CC_get_escape(conn), pptr, token, sizeof(token), &delim, &quote, &dquote, &numeric)) != NULL)
{
unquoted = !(quote || dquote);
if (delim)
{
delimdsp[0] = delim;
delimdsp[1] = '\0';
}
else
delimdsp[0] = '\0';
MYLOG(0, "unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%s', token='%s', ptr='%s'\n", unquoted, quote, dquote, numeric, delimdsp, token, ptr);
old_blevel = blevel;
if (unquoted && blevel == 0)
{
if (in_select)
{
if (!stricmp(token, "distinct"))
{
in_distinct = TRUE;
updatable = FALSE;
MYLOG(0, "DISTINCT\n");
continue;
}
else if (!stricmp(token, "into"))
{
in_select = FALSE;
MYLOG(0, "INTO\n");
stmt->statement_type = STMT_TYPE_CREATE;
SC_set_parse_status(stmt, STMT_PARSE_FATAL);
goto cleanup;
}
else if (!stricmp(token, "from"))
{
if (sqlsvr_check)
{
parse = TRUE;
goto cleanup;
}
in_select = FALSE;
in_from = TRUE;
if (stmt->from_pos < 0 &&
(!strnicmp(pptr, "from", 4)))
{
MYLOG(0, "First From\n");
stmt->from_pos = pptr - stmt->statement;
}
else
MYLOG(0, "FROM\n");
continue;
}
} /* in_select && unquoted && blevel == 0 */
else if ((!stricmp(token, "where") ||
!stricmp(token, "union") ||
!stricmp(token, "intersect") ||
!stricmp(token, "except") ||
!stricmp(token, "order") ||
!stricmp(token, "group") ||
!stricmp(token, "having")))
{
in_from = FALSE;
in_where = TRUE;
if (stmt->where_pos < 0)
stmt->where_pos = pptr - stmt->statement;
MYLOG(0, "%s...\n", token);
if (stricmp(token, "where") &&
stricmp(token, "order"))
{
updatable = FALSE;
break;
}
continue;
}
} /* unquoted && blevel == 0 */
/* check the change of blevel etc */
if (unquoted)
{
if (!stricmp(token, "select"))
{
stoken[0] = '\0';
if (0 == blevel)
{
in_select = TRUE;
MYLOG(0, "SELECT\n");
continue;
}
else
{
MYLOG(0, "SUBSELECT\n");
if (0 == subqlevel)
subqlevel = blevel;
}
}
else if (token[0] == '(')
{
blevel++;
MYLOG(0, "blevel++ -> %d\n", blevel);
/* aggregate function ? */
if (stoken[0] && updatable && 0 == subqlevel)
{
if (stricmp(stoken, "count") == 0 ||
stricmp(stoken, "sum") == 0 ||
stricmp(stoken, "avg") == 0 ||
stricmp(stoken, "max") == 0 ||
stricmp(stoken, "min") == 0 ||
stricmp(stoken, "variance") == 0 ||
stricmp(stoken, "stddev") == 0)
updatable = FALSE;
}
}
else if (token[0] == ')')
{
blevel--;
MYLOG(0, "blevel-- = %d\n", blevel);
if (blevel < subqlevel)
subqlevel = 0;
}
if (blevel >= old_blevel && ',' != delim)
STRCPY_FIXED(stoken, token);
else
stoken[0] = '\0';
}
if (in_select)
{
MYLOG(0, "blevel=%d btoken=%s in_dot=%d in_field=%d tbname=%s\n", blevel, btoken, in_dot, in_field, wfi ? SAFE_NAME(wfi->column_alias) : "<null>");
if (0 == blevel &&
sqlsvr_check &&
dquote &&
'\0' != btoken[0] &&
!in_dot &&
in_field &&
(!column_has_alias))
{
if (include_alias_wo_as(token, btoken))
{
char *news;
column_has_alias = TRUE;
if (NULL != wfi)
STRX_TO_NAME(wfi->column_alias, token);
news = insert_as_to_the_statement(stmt->statement, &pptr, &ptr);
if (news != stmt->statement)
{
free(stmt->statement);
stmt->statement = news;
}
}
}
if (in_expr || in_func)
{
/* just eat the expression */
MYLOG(0, "in_expr=%d or func=%d\n", in_expr, in_func);
if (blevel == 0)
{
if (delim == ',')
{
MYLOG(0, "**** Got comma in_expr/func\n");
in_func = FALSE;
in_expr = FALSE;
in_field = FALSE;
}
else if (unquoted && !stricmp(token, "as"))
{
MYLOG(0, "got AS in_expr\n");
in_func = FALSE;
in_expr = FALSE;
in_as = TRUE;
in_field = TRUE;
}
}
continue;
} /* (in_expr || in_func) && in_select */
if (in_distinct)
{
MYLOG(0, "in distinct\n");
if (unquoted && !stricmp(token, "on"))
{
in_on = TRUE;
MYLOG(0, "got on\n");
continue;
}
if (in_on)
{
in_distinct = FALSE;
in_on = FALSE;
continue; /* just skip the unique on field */
}
MYLOG(0, "done distinct\n");
in_distinct = FALSE;
} /* in_distinct */
if (!in_field)
{
BOOL fi_reuse = FALSE;
if (!token[0])
continue;
column_has_alias = FALSE;
if (!sqlsvr_check)
{
/* if (!(irdflds->nfields % FLD_INCR)) */
if (irdflds->nfields >= allocated_size)
{
MYLOG(0, "reallocing at nfld=%d\n", irdflds->nfields);
new_size = irdflds->nfields + 1;
if (!allocateFields(irdflds, new_size))
{
SC_set_parse_status(stmt, STMT_PARSE_FATAL);
SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for FIELD_INFO.", func);
goto cleanup;
}
fi = irdflds->fi;
allocated_size = irdflds->allocated;
}
wfi = fi[irdflds->nfields];
if (NULL != wfi)
fi_reuse = TRUE;
else
wfi = fi[irdflds->nfields] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
if (NULL == wfi)
{
SC_set_parse_status(stmt, STMT_PARSE_FATAL);
SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for FIELD_INFO(2).", func);
goto cleanup;
}
/* Initialize the field info */
FI_Constructor(wfi, fi_reuse);
wfi->flag = FIELD_PARSING;
}
/* double quotes are for qualifiers */
if (dquote && NULL != wfi)
wfi->dquote = TRUE;
if (quote)
{
if (NULL != wfi)
{
wfi->quote = TRUE;
wfi->column_size = (int) strlen(token);
}
}
else if (numeric)
{
MYLOG(0, "**** got numeric: nfld = %d\n", nfields);
if (NULL != wfi)
wfi->numeric = TRUE;
}
else if (0 == old_blevel && blevel > 0)
{ /* expression */
MYLOG(0, "got EXPRESSION\n");
if (NULL != wfi)
wfi->expr = TRUE;
in_expr = TRUE;
/* continue; */
}
else if (NULL != wfi)
{
STRX_TO_NAME(wfi->column_name, token);
NULL_THE_NAME(wfi->before_dot);
}
if (NULL != wfi)
MYLOG(0, "got field='%s', dot='%s'\n", PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->before_dot));
if (delim == ',')
MYLOG(0, "comma (1)\n");
else
in_field = TRUE;
nfields++;
if (NULL != irdflds)
irdflds->nfields++;
continue;
} /* !in_field */
/*
* We are in a field now
*/
if (!sqlsvr_check)
wfi = fi[irdflds->nfields - 1];
if (in_dot)
{
if (NULL != wfi)
{
if (NAME_IS_VALID(wfi->before_dot))
{
MOVE_NAME(wfi->schema_name, wfi->before_dot);
}
MOVE_NAME(wfi->before_dot, wfi->column_name);
STRX_TO_NAME(wfi->column_name, token);
}
if (delim == ',')
{
MYLOG(0, "in_dot: got comma\n");
in_field = FALSE;
}
in_dot = FALSE;
continue;
}
if (in_as)
{
column_has_alias = TRUE;
if (NULL != wfi)
{
STRX_TO_NAME(wfi->column_alias, token);
MYLOG(0, "alias for field '%s' is '%s'\n", PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->column_alias));
}
in_as = FALSE;
in_field = FALSE;
if (delim == ',')
MYLOG(0, "comma(2)\n");
continue;
}
/* Function */
if (0 == old_blevel && blevel > 0)
{
in_dot = FALSE;
in_func = TRUE;
if (NULL != wfi)
{
wfi->func = TRUE;
/*
* name will have the function name -- maybe useful some
* day
*/
MYLOG(0, "**** got function = '%s'\n", PRINT_NAME(wfi->column_name));
}
continue;
}
if (token[0] == '.')
{
in_dot = TRUE;
MYLOG(0, "got dot\n");
continue;
}
in_dot = FALSE;
if (!stricmp(token, "as"))
{
in_as = TRUE;
MYLOG(0, "got AS\n");
continue;
}
/* otherwise, it's probably an expression */
if (!column_has_alias)
{
in_expr = TRUE;
if (NULL != wfi)
{
wfi->expr = TRUE;
NULL_THE_NAME(wfi->column_name);
wfi->column_size = 0;
}
MYLOG(0, "*** setting expression\n");
}
else
MYLOG(0, "*** may be an alias for a field\n");
if (0 == blevel && ',' == delim)
{
in_expr = in_func = in_field = FALSE;
}
} /* in_select end */
if (in_from || in_where)
{
if (token[0] == ';') /* end of the first command */
{
in_select = in_from = in_where = in_table = FALSE;
break;
}
}
if (in_from)
{
switch (token[0])
{
case '\0':
continue;
case ',':
out_table = TRUE;
continue;
}
if (out_table && !in_table) /* new table */
{
BOOL is_table_name, is_subquery;
in_dot = FALSE;
maybe_join = 0;
if (!dquote)
{
if (token[0] == '(' ||
token[0] == ')')
continue;
}
if (sqlsvr_check)
wti = NULL;
else
{
if (!increaseNtab(stmt, func))
{
SC_set_parse_status(stmt, STMT_PARSE_FATAL);
goto cleanup;
}
ti = stmt->ti;
wti = ti[stmt->ntab - 1];
}
is_table_name = TRUE;
is_subquery = FALSE;
if (dquote)
;
else if (0 == stricmp(token, "select"))
{
MYLOG(0, "got subquery lvl=%d\n", blevel);
is_table_name = FALSE;
is_subquery = TRUE;
}
else if ('(' == ptr[0])
{
MYLOG(0, "got srf? = '%s'\n", token);
is_table_name = FALSE;
}
if (NULL != wti)
{
if (is_table_name)
{
STRX_TO_NAME(wti->table_name, token);
lower_the_name(GET_NAME(wti->table_name), conn, dquote);
MYLOG(0, "got table = '%s'\n", PRINT_NAME(wti->table_name));
}
else
{
NULL_THE_NAME(wti->table_name);
TI_no_updatable(wti);
}
}
if (0 == blevel && delim == ',')
{
out_table = TRUE;
MYLOG(0, "more than 1 tables\n");
}
else
{
out_table = FALSE;
in_table = TRUE;
if (is_subquery)
tbl_blevel = blevel - 1;
else
tbl_blevel = blevel;
}
continue;
}
if (blevel > tbl_blevel)
continue;
/* out_table is FALSE here */
if (!dquote && !in_dot)
{
if (')' == token[0])
continue;
if (stricmp(token, "LEFT") == 0 ||
stricmp(token, "RIGHT") == 0 ||
stricmp(token, "OUTER") == 0 ||
stricmp(token, "FULL") == 0)
{
maybe_join = 1;
in_table = FALSE;
continue;
}
else if (stricmp(token, "INNER") == 0 ||
stricmp(token, "CROSS") == 0)
{
maybe_join = 2;
in_table = FALSE;
continue;
}
else if (stricmp(token, "JOIN") == 0)
{
in_table = FALSE;
out_table = TRUE;
switch (maybe_join)
{
case 1:
SC_set_outer_join(stmt);
break;
case 2:
SC_set_inner_join(stmt);
break;
}
maybe_join = 0;
continue;
}
}
maybe_join = 0;
if (in_table)
{
if (!sqlsvr_check)
wti = ti[stmt->ntab - 1];
if (in_dot)
{
if (NULL != wfi)
{
MOVE_NAME(wti->schema_name, wti->table_name);
STRX_TO_NAME(wti->table_name, token);
lower_the_name(GET_NAME(wti->table_name), conn, dquote);
}
in_dot = FALSE;
continue;
}
if (strcmp(token, ".") == 0)
{
in_dot = TRUE;
continue;
}
if (dquote || stricmp(token, "as"))
{
if (!dquote)
{
if (stricmp(token, "ON") == 0)
{
in_table = FALSE;
continue;
}
}
if (NULL != wti)
{
STRX_TO_NAME(wti->table_alias, token);
MYLOG(0, "alias for table '%s' is '%s'\n", PRINT_NAME(wti->table_name), PRINT_NAME(wti->table_alias));
}
in_table = FALSE;
if (delim == ',')
{
out_table = TRUE;
MYLOG(0, "more than 1 tables\n");
}
}
}
} /* in_from */
}
/*
* Resolve any possible field names with tables
*/
parse = TRUE;
if (sqlsvr_check)
goto cleanup;
/* Resolve field names with tables */
for (i = 0; i < (int) irdflds->nfields; i++)
{
wfi = fi[i];
if (wfi->func || wfi->expr || wfi->numeric)
{
wfi->ti = NULL;
wfi->columntype = wfi->basetype = (OID) 0;
parse = FALSE;
continue;
}
else if (wfi->quote)
{ /* handle as text */
wfi->ti = NULL;
/*
* wfi->type = PG_TYPE_TEXT; wfi->column_size = 0; the
* following may be better
*/
wfi->basetype = PG_TYPE_UNKNOWN;
if (wfi->column_size == 0)
{
wfi->basetype = PG_TYPE_VARCHAR;
wfi->column_size = 254;
}
wfi->length = wfi->column_size;
continue;
}
/* field name contains the schema name */
else if (NAME_IS_VALID(wfi->schema_name))
{
int matchidx = -1;
for (k = 0; k < stmt->ntab; k++)
{
wti = ti[k];
if (!NAMEICMP(wti->table_name, wfi->before_dot))
{
if (!NAMEICMP(wti->schema_name, wfi->schema_name))
{
wfi->ti = wti;
break;
}
else if (NAME_IS_NULL(wti->schema_name))
{
if (matchidx < 0)
matchidx = k;
else
{
SC_set_parse_status(stmt, STMT_PARSE_FATAL);
SC_set_error(stmt, STMT_EXEC_ERROR, "duplicated Table name", func);
SC_reset_updatable(stmt);
goto cleanup;
}
}
}
}
if (matchidx >= 0)
wfi->ti = ti[matchidx];
}
/* it's a dot, resolve to table or alias */
else if (NAME_IS_VALID(wfi->before_dot))
{
for (k = 0; k < stmt->ntab; k++)
{
wti = ti[k];
if (!NAMEICMP(wti->table_alias, wfi->before_dot))
{
wfi->ti = wti;
break;
}
else if (!NAMEICMP(wti->table_name, wfi->before_dot))
{
wfi->ti = wti;
break;
}
}
}
else if (stmt->ntab == 1)
wfi->ti = ti[0];
}
MYLOG(0, "--------------------------------------------\n");
MYLOG(0, "nfld=%d, ntab=%d\n", irdflds->nfields, stmt->ntab);
if (0 == stmt->ntab)
{
SC_set_parse_status(stmt, STMT_PARSE_FATAL);
goto cleanup;
}
for (i = 0; i < (int) irdflds->nfields; i++)
{
wfi = fi[i];
MYLOG(0, "Field %d: expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n", i, wfi->expr, wfi->func, wfi->quote, wfi->dquote, wfi->numeric, PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->column_alias), PRINT_NAME(wfi->before_dot));
if (wfi->ti)
MYLOG(0, " ----> table_name='%s', table_alias='%s'\n", PRINT_NAME(wfi->ti->table_name), PRINT_NAME(wfi->ti->table_alias));
}
for (i = 0; i < stmt->ntab; i++)
{
wti = ti[i];
MYLOG(0, "Table %d: name='%s', alias='%s'\n", i, PRINT_NAME(wti->table_name), PRINT_NAME(wti->table_alias));
}
/*
* Now save the SQLColumns Info for the parse tables
*/
/* Call SQLColumns for each table and store the result */
if (stmt->ntab > 1)
updatable = FALSE;
else if (stmt->from_pos < 0)
updatable = FALSE;
for (i = 0; i < stmt->ntab; i++)
{
/* See if already got it */
wti = ti[i];
if (!getCOLIfromTI(func, NULL, stmt, 0, &wti))
break;
}
if (STMT_PARSE_FATAL == SC_parsed_status(stmt))
{
goto cleanup;
}
MYLOG(0, "Done PG_Columns\n");
/*
* Now resolve the fields to point to column info
*/
if (updatable && 1 == stmt->ntab)
updatable = TI_is_updatable(stmt->ti[0]);
for (i = 0; i < (int) irdflds->nfields;)
{
wfi = fi[i];
wfi->updatable = updatable;
/* Dont worry about functions or quotes */
if (wfi->func || wfi->quote || wfi->numeric)
{
wfi->updatable = FALSE;
i++;
continue;
}
/* Stars get expanded to all fields in the table */
else if (SAFE_NAME(wfi->column_name)[0] == '*')
{
char do_all_tables;
Int2 total_cols,
cols,
increased_cols;
MYLOG(0, "expanding field %d\n", i);
total_cols = 0;
if (wfi->ti) /* The star represents only the qualified
* table */
total_cols = (Int2) QR_get_num_cached_tuples(wfi->ti->col_info->result);
else
{ /* The star represents all tables */
/* Calculate the total number of columns after expansion */
for (k = 0; k < stmt->ntab; k++)
total_cols += (Int2) QR_get_num_cached_tuples(ti[k]->col_info->result);
}
increased_cols = total_cols - 1;
/* Allocate some more field pointers if necessary */
new_size = irdflds->nfields + increased_cols;
MYLOG(0, "k=%d, increased_cols=%d, allocated_size=%d, new_size=%d\n", k, increased_cols, allocated_size, new_size);
if (new_size > allocated_size)
{
int new_alloc = new_size;
MYLOG(0, "need more cols: new_alloc = %d\n", new_alloc);
if (!allocateFields(irdflds, new_alloc))
{
SC_set_parse_status(stmt, STMT_PARSE_FATAL);
goto cleanup;
}
fi = irdflds->fi;
allocated_size = irdflds->allocated;
}
/*
* copy any other fields (if there are any) up past the
* expansion
*/
for (j = irdflds->nfields - 1; j > i; j--)
{
MYLOG(0, "copying field %d to %d\n", j, increased_cols + j);
fi[increased_cols + j] = fi[j];
}
MYLOG(0, "done copying fields\n");
/* Set the new number of fields */
irdflds->nfields += increased_cols;
MYLOG(0, "irdflds->nfields now at %d\n", irdflds->nfields);
/* copy the new field info */
do_all_tables = (wfi->ti ? FALSE : TRUE);
wfi = NULL;
for (k = 0; k < (do_all_tables ? stmt->ntab : 1); k++)
{
TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;
cols = (Int2) QR_get_num_cached_tuples(the_ti->col_info->result);
for (n = 0; n < cols; n++)
{
FIELD_INFO *afi;
BOOL reuse = TRUE;
MYLOG(0, "creating field info: n=%d\n", n);
/* skip malloc (already did it for the Star) */
if (k > 0 || n > 0)
{
MYLOG(0, "allocating field info at %d\n", n + i);
fi[n + i] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
if (fi[n + i] == NULL)
{
SC_set_parse_status(stmt, STMT_PARSE_FATAL);
goto cleanup;
}
reuse = FALSE;
}
afi = fi[n + i];
/* Initialize the new space (or the * field) */
FI_Constructor(afi, reuse);
afi->ti = the_ti;
MYLOG(0, "about to copy at %d\n", n + i);
getColInfo(the_ti->col_info, afi, n);
afi->updatable = updatable;
MYLOG(0, "done copying\n");
}
i += cols;
MYLOG(0, "i now at %d\n", i);
}
}
/*
* We either know which table the field was in because it was
* qualified with a table name or alias -OR- there was only 1
* table.
*/
else if (wfi->ti)
{
if (!searchColInfo(fi[i]->ti->col_info, wfi))
{
parse = FALSE;
wfi->updatable = FALSE;
}
i++;
}
/* Don't know the table -- search all tables in "from" list */
else
{
for (k = 0; k < stmt->ntab; k++)
{
if (searchColInfo(ti[k]->col_info, wfi))
{
wfi->ti = ti[k]; /* now know the table */
break;
}
}
if (k >= stmt->ntab)
{
parse = FALSE;
wfi->updatable = FALSE;
}
i++;
}
}
if (check_hasoids && updatable)
CheckHasOids(stmt);
SC_set_parse_status(stmt, parse ? STMT_PARSE_COMPLETE : STMT_PARSE_INCOMPLETE);
for (i = 0; i < (int) irdflds->nfields; i++)
{
wfi = fi[i];
wfi->flag &= ~FIELD_PARSING;
if (0 != wfi->columntype || 0 != wfi->basetype)
wfi->flag |= FIELD_PARSED_OK;
}
SC_set_updatable(stmt, updatable);
cleanup:
#undef return
if (!sqlsvr_check && STMT_PARSE_FATAL == SC_parsed_status(stmt))
{
SC_initialize_cols_info(stmt, FALSE, FALSE);
parse = FALSE;
}
MYLOG(0, "laving parse=%d, parse_status=%d\n", parse, SC_parsed_status(stmt));
return parse;
}
char
parse_statement(StatementClass *stmt, BOOL check_hasoids)
{
return parse_the_statement(stmt, check_hasoids, FALSE);
}
char
parse_sqlsvr(StatementClass *stmt)
{
return parse_the_statement(stmt, FALSE, TRUE);
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/zhangtingtingting/openGauss-connector-odbc.git
git@gitee.com:zhangtingtingting/openGauss-connector-odbc.git
zhangtingtingting
openGauss-connector-odbc
openGauss-connector-odbc
master

搜索帮助