/* * See the file LICENSE for redistribution information. * * Copyright (c) 1996, 2010 Oracle and/or its affiliates. All rights reserved. * */ /* * The functions in this compilation unit are those related to * building the schema model during the parsing of a SQL source file. * Most of the functions that have name beginning with "sqlite3..." * are invoked by the sqlite parser as it recognizes bits of syntax. */ #include #include "db_sql_codegen.h" DB_SCHEMA the_schema; PARSE_PROGRESS the_parse_progress; int maxbinsz; /* keeps track of the largest binary field */ /* * Extract a name from sqlite token structure. Returns allocated memory. */ 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; } /* * Allocate, populate, and return memory for an ENTITY struct. If * there is a malloc failure, set an error message in the Parse * object and return NULL. */ 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; } /* * Allocate, populate, and return memory for an ATTRIBUTE struct. If * there is a malloc failure, set an error message in the Parse * object and return NULL. */ 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; } /* * Allocate, populate, and return memory for an ATTR_TYPE struct. If * there is a malloc failure, set an error message in the Parse * object and return NULL. */ 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; } /* * Allocate, populate, and return memory for an DB_INDEX struct. If * there is a malloc failure, set the error message in the Parse * object and return NULL. */ 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() { /* * The entity under construction is always at the tail of the * entity list */ ENTITY *entity = the_schema.entities_tail; assert(entity); return entity; } static ATTRIBUTE * get_current_attribute() { ENTITY *entity; ATTRIBUTE *attr; /* * The attribute under construction is always at the tail of * the attribute list belonging to the entity at the tail of * the entity list. */ 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); /* no-op */ } 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; /* Parser context */ Token *pName1; /* First part of the name of the table or view */ Token *pName2; /* Second part of the name of the table or view */ int isTemp; /* True if this is a TEMP table */ int isView; /* True if this is a VIEW */ int isVirtual; /* True if this is a VIRTUAL table */ int noErr; /* Do nothing if table already exists */ { 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; /* * We don't allow the second pName, for now. Note for future * reference: if pName2 is set, then pName1 is the database * name, and pname2 is the table name. */ 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; } /* * This function maps SQL types into the closest equivalent * available using plain C-language types. */ 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; /* * Make a copy of the original token, so that we can modify it * to remove spaces, and break it up into multiple strings by * inserting null characters. */ 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); /* Remove any spaces that t might contain. */ /* * If t contains a parenthesis, then it is a SQL type that has * either a dimension, such as VARCHAR(255); or a precision, * and possibly a scale, such as NUMBER(15, 2). We need to * extract these values. Sqlite's parser does not decompose * these tokens for us. */ if ((p = strchr(t, '(')) != NULL) { /* * Split the token into two strings by replacing the * parenthesis with a null character. The pointer t * is now a simple type name, and p points to the * first parenthesized parameter. */ *p++ = '\0'; /* * There should be a right paren somewhere. * Actually, the parser probably guarantees this at least. */ if ((q = strchr(p, ')')) == NULL) { sqlite3ErrorMsg(pParse, "Missing right parenthesis in type expression %s\n", token); goto free_allocated_on_error; } /* * null the paren, to make the parameter list a * null-terminated string */ *q = '\0'; /* * Is there a comma in the parameter list? If so, * we'll isolate the first parameter */ if ((q = strchr(p, ',')) != NULL) *q++ = '\0'; /* q now points to the second param */ 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; } /* If there was a second parameter, parse it */ 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; } } } /* OK, now the simple mapping. */ 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 ) { /* * Oracle Number type: if scale is zero, it's an integer. * Otherwise, call it a floating point */ if (scale == 0) { /* A 10 digit decimal needs a long */ 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); /* Type will be NULL unless make_attrtype was called, and succeeded. */ 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; /* Parsing context */ ExprList *pList; /* List of field names to be indexed */ int onError; /* What to do with a uniqueness conflict */ int autoInc; /* True if the AUTOINCREMENT keyword is present */ int sortOrder; /* SQLITE_SO_ASC or SQLITE_SO_DESC */ { 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; } /* * Add a new element to the end of an expression list. If pList is * initially NULL, then create a new expression list. */ ExprList * sqlite3ExprListAppend(pParse, pList, pExpr, pName) Parse *pParse; /* Parsing context */ ExprList *pList; /* List to which to append. Might be NULL */ Expr *pExpr; /* Expression to be appended */ Token *pName; /* AS keyword for the expression */ { 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 --; /* undo allocation of pItem */ 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); /* no-op */ } /* * Append a new table name to the given SrcList. Create a new SrcList * if need be. If pList is initially NULL, then create a new * src list. * * We don't have a Parse object here, so we can't use name_from_token, * or report an error via the usual Parse.rc mechanism. Just emit a * message on stderr if there is a problem. Returning NULL from this * function will cause the parser to fail, so any message we print * here will be followed by the usual syntax error message. */ SrcList * sqlite3SrcListAppend(db, pList, pTable, pDatabase) sqlite3 *db; /* unused */ SrcList *pList; /* Append to this SrcList */ Token *pTable; /* Table to append */ Token *pDatabase; /* Database of the table, not used at this time */ { 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; } /* * We parse, and allow, foreign key constraints, but currently do not * use them. */ void sqlite3CreateForeignKey(pParse, pFromCol, pTo, pToCol, flags) Parse *pParse; /* Parsing context */ ExprList *pFromCol; /* Columns in that reference other table */ Token *pTo; /* Name of the other table */ ExprList *pToCol; /* Columns in the other table */ int flags; /* Conflict resolution algorithms. */ { 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); /* no-op */ } void sqlite3CreateIndex(pParse, pName1, pName2, pTblName, pList, onError, pStart, pEnd, sortOrder, ifNotExist) Parse *pParse; /* All information about this parse */ Token *pName1; /* First part of index name. May be NULL */ Token *pName2; /* Second part of index name. May be NULL */ SrcList *pTblName; /* Table to index. Use pParse->pNewTable if 0 */ ExprList *pList; /* A list of columns to be indexed */ int onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ Token *pStart; /* The CREATE token that begins this statement */ Token *pEnd; /* The ")" that closes the CREATE INDEX statement */ int sortOrder; /* Sort order of primary key when pList==NULL */ int ifNotExist; /* Omit error if index already exists */ { 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; /* Parse context */ Token *pCons; /* The ',' token after the last column defn. */ Token *pEnd; /* The final ')' token in the CREATE TABLE */ Select *pSelect; /* Select from a "CREATE ... AS SELECT" */ { 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); /* no-op */ }