#include <ctype.h>
#include "db_sql_codegen.h"
DB_SCHEMA the_schema;
PARSE_PROGRESS the_parse_progress;
int maxbinsz;
static char *
name_from_token(t, pParse)
Token *t;
Parse *pParse;
{
char *s;
if (t == NULL || t->n <= 0) {
sqlite3ErrorMsg(pParse,
"Extracting name from a null or empty token");
return NULL;
}
s = calloc(1, t->n + 1);
if (s == NULL) {
sqlite3ErrorMsg(pParse, "Malloc failed");
return NULL;
}
memcpy(s, (char*)t->z, t->n);
sqlite3Dequote(s);
return s;
}
static ENTITY *
make_entity(name, pParse)
char *name;
Parse *pParse;
{
ENTITY *entity;
entity = calloc(1, sizeof(ENTITY));
if (entity == NULL) {
sqlite3ErrorMsg(pParse, "Malloc failed");
return NULL;
}
entity->name = name;
entity->line_number = line_number;
entity->dbtype = "DB_BTREE";
entity->transactional = the_schema.environment.transactional;
return entity;
}
static ATTRIBUTE *
make_attribute(name, pParse)
char *name;
Parse *pParse;
{
ATTRIBUTE *attribute;
attribute = calloc(1, sizeof(ATTRIBUTE));
if (attribute == NULL) {
sqlite3ErrorMsg(pParse, "Malloc failed");
return NULL;
}
attribute->name = name;
return attribute;
}
static ATTR_TYPE *
make_attrtype(token, ctype, dimension, is_array, is_string, pParse)
char *token;
char *ctype;
int dimension;
int is_array;
int is_string;
Parse *pParse;
{
ATTR_TYPE *type;
type = calloc(1, sizeof(ATTR_TYPE));
if (type == NULL) {
sqlite3ErrorMsg(pParse, "Malloc failed");
return NULL;
}
type->sql_token = token;
type->c_type = ctype;
type->array_dim = dimension;
type->is_array = is_array;
type->is_string = is_string;
return type;
}
static DB_INDEX *
make_index(name, primary, attribute, pParse)
char *name;
ENTITY *primary;
ATTRIBUTE *attribute;
Parse *pParse;
{
DB_INDEX *idx;
idx = calloc(1, sizeof(DB_INDEX));
if (idx == NULL) {
sqlite3ErrorMsg(pParse, "Malloc failed");
return NULL;
}
idx->name = name;
idx->primary = primary;
idx->attribute = attribute;
idx->line_number = line_number;
idx->dbtype = "DB_BTREE";
return idx;
}
static void
add_entity(entity)
ENTITY *entity;
{
if (the_schema.entities_tail == NULL)
the_schema.entities_tail = the_schema.entities_head = entity;
else {
the_schema.entities_tail->next = entity;
the_schema.entities_tail = entity;
}
}
static void
add_index(idx)
DB_INDEX *idx;
{
if (the_schema.indexes_tail == NULL)
the_schema.indexes_tail = the_schema.indexes_head = idx;
else {
the_schema.indexes_tail->next = idx;
the_schema.indexes_tail = idx;
}
}
static void
add_attribute(entity, attr)
ENTITY *entity;
ATTRIBUTE * attr;
{
if (entity->attributes_tail == NULL) {
entity->attributes_head = entity->attributes_tail = attr;
} else {
entity->attributes_tail->next = attr;
entity->attributes_tail = attr;
}
}
static ENTITY *
get_current_entity()
{
ENTITY *entity = the_schema.entities_tail;
assert(entity);
return entity;
}
static ATTRIBUTE *
get_current_attribute()
{
ENTITY *entity;
ATTRIBUTE *attr;
entity = get_current_entity();
attr = entity->attributes_tail;
assert(attr);
return attr;
}
static ENTITY *
get_entity_by_name(sought_name)
char *sought_name;
{
ENTITY *e;
for (e = the_schema.entities_head; e; e = e->next)
if (strcasecmp(sought_name, e->name) == 0)
return e;
return NULL;
}
static ATTRIBUTE *
get_attribute_by_name(in_entity, sought_name)
ENTITY * in_entity;
char *sought_name;
{
ATTRIBUTE *a;
for (a = in_entity->attributes_head; a; a = a->next)
if (strcasecmp(sought_name, a->name) == 0)
return a;
return NULL;
}
static DB_INDEX *
get_index_by_name(sought_name)
char *sought_name;
{
DB_INDEX *idx;
for (idx = the_schema.indexes_head; idx; idx = idx->next)
if (strcasecmp(sought_name, idx->name) == 0)
return idx;
return NULL;
}
void
sqlite3BeginParse(Parse *pParse, int explainFlag)
{
COMPQUIET(pParse, NULL);
COMPQUIET(explainFlag, 0);
}
void
bdb_create_database(Token *name, Parse *pParse) {
if (the_schema.environment.name != NULL)
sqlite3ErrorMsg(pParse,
"Encountered two CREATE DATABASE statements; only one \
is allowed");
if ((the_schema.environment.name =
name_from_token(name, pParse)) == NULL)
return;
the_schema.environment.line_number = line_number;
the_schema.environment.cache_size = 0;
the_schema.environment.transactional = txnflag;
the_parse_progress.last_event = PE_ENVIRONMENT;
}
void
sqlite3StartTable(pParse, pName1, pName2, isTemp, isView, isVirtual, noErr)
Parse *pParse;
Token *pName1;
Token *pName2;
int isTemp;
int isView;
int isVirtual;
int noErr;
{
char *name, *name2;
ENTITY *entity;
DB_INDEX *idx;
COMPQUIET(isTemp, 0);
COMPQUIET(isView, 0);
COMPQUIET(isVirtual, 0);
COMPQUIET(noErr, 0);
if (the_schema.environment.name == NULL) {
sqlite3ErrorMsg(pParse,
"Please specify CREATE DATABASE before CREATE TABLE");
return;
}
if ((name = name_from_token(pName1, pParse)) == NULL)
return;
name2 = NULL;
if (! (pName2 == NULL || pName2->n == 0) ) {
name2 = name_from_token(pName2, pParse);
sqlite3ErrorMsg(pParse,
"The table name must be simple: %s.%s",
name, name2);
goto free_allocated_on_error;
}
if ((entity = get_entity_by_name(name)) != NULL) {
sqlite3ErrorMsg(pParse,
"Found two declarations of a table named %s, at lines \
%d and %d",
name, entity->line_number, line_number);
goto free_allocated_on_error;
}
if ((idx = get_index_by_name(name)) != NULL) {
sqlite3ErrorMsg(pParse,
"The entity named %s on line %d has the same name as \
the index at line %d. This is not allowed.",
name, line_number, idx->line_number);
goto free_allocated_on_error;
}
if ((entity = make_entity(name, pParse)) == NULL)
goto free_allocated_on_error;
the_parse_progress.last_event = PE_ENTITY;
the_parse_progress.last_entity = entity;
add_entity(entity);
return;
free_allocated_on_error:
if (name != NULL) free(name);
if (name2 != NULL) free(name2);
}
void
sqlite3AddColumn(Parse *pParse, Token *pName)
{
ENTITY *entity;
ATTRIBUTE *attr;
char *name;
if ((name = name_from_token(pName, pParse)) == NULL)
return;
entity = get_current_entity();
if ((attr = get_attribute_by_name(entity, name)) != NULL) {
sqlite3ErrorMsg(pParse,
"The table %s contains two columns with the same name %s; \
this is not allowed.",
entity->name, name);
goto free_allocated_on_error;
}
if ((attr = make_attribute(name, pParse)) == NULL)
goto free_allocated_on_error;
the_parse_progress.last_event = PE_ATTRIBUTE;
the_parse_progress.last_attribute = attr;
add_attribute(entity, attr);
return;
free_allocated_on_error:
if (name != NULL) free(name);
}
static void
delete_spaces(char *s) {
char *p;
p = s;
while (*p) {
if (!isspace(*p))
*s++ = *p;
p++;
}
*s = *p;
}
static ATTR_TYPE *
map_sql_type(pParse, token)
Parse *pParse;
char *token;
{
int dimension, scale, is_array, is_string;
size_t len;
char *p, *q;
ATTR_TYPE *type;
char *t;
char *ctype;
ctype = NULL;
type = NULL;
scale = 0;
len = strlen(token) + 1;
t = malloc(len);
if (t == NULL) {
sqlite3ErrorMsg(pParse, "Malloc failed");
return NULL;
}
memcpy(t, token, len);
dimension = 0;
is_array = 0;
is_string = 0;
delete_spaces(t);
if ((p = strchr(t, '(')) != NULL) {
*p++ = '\0';
if ((q = strchr(p, ')')) == NULL) {
sqlite3ErrorMsg(pParse,
"Missing right parenthesis in type expression %s\n",
token);
goto free_allocated_on_error;
}
*q = '\0';
if ((q = strchr(p, ',')) != NULL)
*q++ = '\0';
dimension = atoi(p);
if (dimension == 0) {
sqlite3ErrorMsg(pParse,
"Non-numeric or zero size parameter in type \
expression %s\n",
token);
goto free_allocated_on_error;
}
scale = 0;
if (q != NULL && *q != '\0') {
if (strchr(q, ',') == NULL && isdigit(*q)) {
scale = atoi(q);
} else {
sqlite3ErrorMsg(pParse,
"Unexpected value for second parameter in \
type expression %s\n",
token);
goto free_allocated_on_error;
}
}
}
q = t;
while (*q) {
*q = tolower(*q);
q++;
}
if (strcmp(t, "bin") == 0) {
ctype = "char";
is_array = 1;
} else if (strcmp(t, "varbin") == 0) {
ctype = "char";
is_array = 1;
} else if (strcmp(t, "char") == 0) {
ctype = "char";
is_array = 1;
is_string = 1;
} else if (strcmp(t, "varchar") == 0) {
ctype = "char";
is_array = 1;
is_string = 1;
} else if (strcmp(t, "varchar2") == 0) {
ctype = "char";
is_array = 1;
is_string = 1;
} else if (strcmp(t, "bit") == 0)
ctype = "char";
else if (strcmp(t, "tinyint") == 0)
ctype = "char";
else if (strcmp(t, "smallint") == 0)
ctype = "short";
else if (strcmp(t, "integer") == 0)
ctype = "int";
else if (strcmp(t, "int") == 0)
ctype = "int";
else if (strcmp(t, "bigint") == 0)
ctype = "long";
else if (strcmp(t, "real") == 0)
ctype = "float";
else if (strcmp(t, "double") == 0)
ctype = "double";
else if (strcmp(t, "float") == 0)
ctype = "double";
else if (strcmp(t, "decimal") == 0)
ctype = "double";
else if (strcmp(t, "numeric") == 0)
ctype = "double";
else if (strcmp(t, "number") == 0 ) {
if (scale == 0) {
if (dimension < 9)
ctype = "int";
else
ctype = "long";
} else {
if (dimension < 7 )
ctype = "float";
else
ctype = "double";
}
}
else {
sqlite3ErrorMsg(pParse,
"Unsupported type %s\n",
token);
goto free_allocated_on_error;
}
if (is_array) {
if (dimension < 1) {
sqlite3ErrorMsg(pParse,
"Zero dimension not allowed for %s",
token);
goto free_allocated_on_error;
}
if ((!is_string) && dimension > maxbinsz)
maxbinsz = dimension;
}
if (is_string && dimension < 2)
fprintf(stderr,
"Warning: dimension of string \"%s %s\" \
is too small to hold a null-terminated string.",
get_current_attribute()->name, token);
type = make_attrtype(token, ctype, dimension, is_array,
is_string, pParse);
free_allocated_on_error:
free(t);
return (type);
}
void
sqlite3AddColumnType(pParse, pType)
Parse *pParse;
Token *pType;
{
char *type;
ATTRIBUTE *attr;
if ((type = name_from_token(pType, pParse)) == NULL)
return;
attr = get_current_attribute();
attr->type = map_sql_type(pParse, type);
}
void
sqlite3AddPrimaryKey(pParse, pList, onError, autoInc, sortOrder)
Parse *pParse;
ExprList *pList;
int onError;
int autoInc;
int sortOrder;
{
ENTITY *entity;
ATTRIBUTE *attr;
COMPQUIET(pParse, NULL);
COMPQUIET(pList, NULL);
COMPQUIET(onError, 0);
COMPQUIET(autoInc, 0);
COMPQUIET(sortOrder, 0);
entity = get_current_entity();
attr = get_current_attribute();
entity->primary_key = attr;
}
ExprList *
sqlite3ExprListAppend(pParse, pList, pExpr, pName)
Parse *pParse;
ExprList *pList;
Expr *pExpr;
Token *pName;
{
if ( pList == NULL ) {
pList = calloc(1, sizeof(ExprList));
if (pList == NULL) {
sqlite3ErrorMsg(pParse, "Malloc failed");
return NULL;
}
}
if (pList->nAlloc <= pList->nExpr) {
struct ExprList_item *a;
int n = pList->nAlloc*2 + 4;
a = realloc(pList->a, n * sizeof(pList->a[0]));
if ( a == NULL ) {
sqlite3ErrorMsg(pParse, "Malloc failed");
return NULL;
}
pList->a = a;
pList->nAlloc = n;
}
if ( pExpr || pName ) {
struct ExprList_item *pItem = &pList->a[pList->nExpr++];
memset(pItem, 0, sizeof(*pItem));
if ((pItem->zName = name_from_token(pName, pParse)) == NULL) {
pList->nExpr --;
return pList;
}
pItem->pExpr = pExpr;
}
return pList;
}
void
sqlite3ExprListCheckLength(pParse, pElist, zObject)
Parse *pParse;
ExprList *pElist;
const char *zObject;
{
COMPQUIET(pParse, NULL);
COMPQUIET(pElist, NULL);
COMPQUIET(zObject, NULL);
}
SrcList *
sqlite3SrcListAppend(db, pList, pTable, pDatabase)
sqlite3 *db;
SrcList *pList;
Token *pTable;
Token *pDatabase;
{
struct SrcList_item *pItem;
char *table_name;
COMPQUIET(db, NULL);
COMPQUIET(pDatabase, NULL);
table_name = NULL;
if (pList == NULL) {
pList = calloc(1, sizeof(SrcList));
if (pList == NULL) {
fprintf(stderr, "Malloc failure\n");
return NULL;
}
pList->nAlloc = 1;
}
if (pList->nSrc >= pList->nAlloc) {
SrcList *pNew;
pList->nAlloc *= 2;
pNew = realloc(pList,
sizeof(*pList) + (pList->nAlloc-1)*sizeof(pList->a[0]));
if (pNew == NULL) {
fprintf(stderr, "Malloc failure\n");
return NULL;
}
pList = pNew;
}
pItem = &pList->a[pList->nSrc];
memset(pItem, 0, sizeof(pList->a[0]));
if (pTable == NULL || pTable->n <= 0) {
fprintf(stderr,
"Extracting name from a null or empty token\n");
return NULL;
}
table_name = calloc(1, pTable->n + 1);
if (table_name == NULL) {
fprintf(stderr, "Malloc failure\n");
return NULL;
}
memcpy(table_name, (char*)pTable->z, pTable->n);
pItem->zName = table_name;
pItem->zDatabase = NULL;
pItem->iCursor = -1;
pItem->isPopulated = 0;
pList->nSrc++;
return pList;
}
void
sqlite3CreateForeignKey(pParse, pFromCol, pTo, pToCol, flags)
Parse *pParse;
ExprList *pFromCol;
Token *pTo;
ExprList *pToCol;
int flags;
{
char * s;
COMPQUIET(flags, 0);
if (debug) {
if ((s = name_from_token(pTo, pParse)) == NULL)
return;
fprintf(stderr, "Foreign Key Constraint not implemented: \
FromTable %s FromCol %s ToTable %s ToCol %s\n",
get_current_entity()->name, pFromCol->a->zName,
s, pToCol->a->zName);
free(s);
}
}
void
sqlite3DeferForeignKey(Parse *pParse, int isDeferred)
{
COMPQUIET(pParse, NULL);
COMPQUIET(isDeferred, 0);
}
void
sqlite3CreateIndex(pParse, pName1, pName2, pTblName, pList,
onError, pStart, pEnd, sortOrder, ifNotExist)
Parse *pParse;
Token *pName1;
Token *pName2;
SrcList *pTblName;
ExprList *pList;
int onError;
Token *pStart;
Token *pEnd;
int sortOrder;
int ifNotExist;
{
ENTITY *e, *extra_entity;
ATTRIBUTE *a;
DB_INDEX *idx;
char *entity_name, *attribute_name, *index_name;
COMPQUIET(pName2, NULL);
COMPQUIET(onError, 0);
COMPQUIET(pStart, NULL);
COMPQUIET(pEnd, NULL);
COMPQUIET(sortOrder, 0);
COMPQUIET(ifNotExist, 0);
entity_name = pTblName->a->zName;
attribute_name = pList->a->zName;
if ((index_name = name_from_token(pName1, pParse)) == NULL)
return;
e = get_entity_by_name(entity_name);
if (e == NULL) {
sqlite3ErrorMsg(pParse, "Index %s names unknown table %s",
index_name, entity_name);
goto free_allocated_on_error;
}
a = get_attribute_by_name(e, attribute_name);
if (a == NULL) {
sqlite3ErrorMsg(pParse,
"Index %s names unknown column %s in table %s",
index_name, attribute_name, entity_name);
goto free_allocated_on_error;;
}
if ((idx = get_index_by_name(index_name)) != NULL) {
sqlite3ErrorMsg(pParse,
"Found two declarations of an index named %s, \
at lines %d and %d",
index_name, idx->line_number, line_number);
goto free_allocated_on_error;;
}
if ((extra_entity = get_entity_by_name(index_name)) != NULL) {
sqlite3ErrorMsg(pParse,
"The index named %s on line %d has the same name as the \
table at line %d. This is not allowed.",
index_name, line_number,
extra_entity->line_number);
goto free_allocated_on_error;
}
if ((idx = make_index(index_name, e, a, pParse)) == NULL)
goto free_allocated_on_error;
the_parse_progress.last_event = PE_INDEX;
the_parse_progress.last_index = idx;
add_index(idx);
return;
free_allocated_on_error:
if (index_name != NULL)
free(index_name);
}
void sqlite3EndTable(pParse, pCons, pEnd, pSelect)
Parse *pParse;
Token *pCons;
Token *pEnd;
Select *pSelect;
{
COMPQUIET(pParse, NULL);
COMPQUIET(pCons, NULL);
COMPQUIET(pEnd, NULL);
COMPQUIET(pSelect, NULL);
the_parse_progress.last_event = PE_ENTITY;
}
void
sqlite3FinishCoding(pParse)
Parse *pParse;
{
COMPQUIET(pParse, NULL);
}