1/* 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996-2009 Oracle. All rights reserved. 5 * 6 */ 7 8/* 9 * These are functions related to parsing and handling hint comments 10 * embedded in the input SQL DDL source. Hint comments convey BDB 11 * configuration information that cannot be represented in SQL DDL. 12 */ 13 14#include <ctype.h> 15#include "db_sql.h" 16 17static void 18hc_warn(char *fmt, ...) 19{ 20 va_list ap; 21 va_start(ap, fmt); 22 fprintf(stderr, "Warning: "); 23 vfprintf(stderr, fmt, ap); 24 fprintf(stderr, ", near line %d\n", line_number); 25 26 va_end(ap); 27} 28 29/* 30 * Return a static copy of the given string, with the given length, in 31 * which all whitespace has been removed 32 */ 33static char * 34static_copy_minus_whitespace(in, len) 35 const char *in; 36 int len; 37{ 38#define smw_bufsiz 10240 39 static char out[smw_bufsiz]; 40 41 int in_i; 42 int out_i; 43 int in_quote; 44 45 in_quote = 0; 46 for (in_i = out_i = 0; in_i < len && in[in_i] != '\0'; in_i++) { 47 if (in[in_i] == '"') { 48 if (in_quote) in_quote = 0; 49 else in_quote = 1; 50 } 51 52 if (in_quote || ! isspace(in[in_i])) { 53 out[out_i++] = in[in_i]; 54 assert(out_i < smw_bufsiz); 55 } 56 } 57 58 out[out_i] = '\0'; 59 60 return out; 61} 62 63/* 64 * Extract a string from the given token. The returned copy is static 65 * and has had all whitespace removed. 66 */ 67static char * 68hint_comment_from_token(t) 69 Token *t; 70{ 71 int len; 72 char *p; 73 74 len = 0; 75 p = NULL; 76 if (t == NULL) 77 return NULL; 78 79 /* The token should be a whole comment; verify that */ 80 81 if (t->z[0] == '/') { 82 assert(t->n >= 4 && 83 t->z[1] == '*' && 84 t->z[t->n - 2] == '*' && 85 t->z[t->n - 1] == '/'); 86 p = ((char *)t->z) + 2; 87 len = t->n - 4; 88 } else if (t->z[0] == '-') { 89 assert(t->n >= 3 && 90 t->z[1] == '-'); 91 p = ((char *)t->z) + 2; 92 len = t->n - 2; 93 } 94 95 assert(p != NULL); 96 97 if (*p != '+') /* the hint comment indicator */ 98 return NULL; 99 100 return static_copy_minus_whitespace(p+1, len-1); 101} 102 103/* 104 * Break a string into two parts at the delimiting char. The left 105 * token is returned, while the right token, if any, is placed in 106 * *rest. If found, the delimiting char in the input string is 107 * replaced with a null char, to terminate the left token string. 108 */ 109static char * 110split(in, delimiter, rest) 111 char *in; 112 char delimiter; 113 char **rest; 114{ 115 char *p; 116 117 *rest = NULL; 118 119 for (p = in; ! (*p == delimiter || *p == '\0'); p++) 120 ; 121 122 if (*p != '\0') { 123 *rest = p + 1; 124 *p = '\0'; 125 } 126 127 return in; 128} 129 130/* 131 * This is basically strtoul with multipliers for suffixes such as k, 132 * m, g for kilobytes, megabytes, and gigabytes 133 */ 134static 135unsigned long int parse_integer(s) 136 char *s; 137{ 138 unsigned long int x; 139 char *t; 140 141 x = strtoul(s, &t, 0); 142 if (s == t) 143 hc_warn("unparseable integer string %s", s); 144 145 146 switch(*t) { 147 case '\0': 148 break; 149 case 'k': 150 case 'K': 151 x = x * KILO; 152 t++; 153 break; 154 case 'm': 155 case 'M': 156 x = x * MEGA; 157 t++; 158 break; 159 case 'g': 160 case 'G': 161 x = x * GIGA; 162 t++; 163 break; 164 } 165 166 if (*t != '\0') 167 hc_warn("unrecognized characters in integer string %s", s); 168 169 return x; 170} 171 172static void 173apply_environment_property(key, value) 174 char *key; 175 char *value; 176{ 177 if (strcasecmp(key, "CACHESIZE") == 0) { 178 the_schema.environment.cache_size = parse_integer(value); 179 } else { 180 hc_warn("Unrecognized environment property %s", key); 181 } 182} 183 184static void 185set_dbtype(entity, value) 186 ENTITY *entity; 187 char *value; 188{ 189 if (strcasecmp(value, "btree") == 0) { 190 entity->dbtype = "DB_BTREE"; 191 } else if (strcasecmp(value, "hash") == 0) { 192 entity->dbtype = "DB_HASH"; 193 } else { 194 hc_warn( 195"unknown DBTYPE %s for antecedent %s, using default of DB_BTREE", 196 value, entity->name); 197 entity->dbtype = "DB_BTREE"; 198 } 199} 200 201static void 202set_idx_dbtype(idx, value) 203 DB_INDEX *idx; 204 char *value; 205{ 206 if (strcasecmp(value, "btree") == 0) { 207 idx->dbtype = "DB_BTREE"; 208 } else if (strcasecmp(value, "hash") == 0) { 209 idx->dbtype = "DB_HASH"; 210 } else { 211 hc_warn( 212"unknown DBTYPE %s for antecedent %s, using default of DB_BTREE", 213 value, idx->name); 214 idx->dbtype = "DB_BTREE"; 215 } 216} 217 218static void 219apply_entity_property(key, value, entity) 220 char *key; 221 char *value; 222 ENTITY *entity; 223{ 224 if (strcasecmp(key, "DBTYPE") == 0) { 225 set_dbtype(entity, value); 226 } else { 227 hc_warn("Unrecognized entity property %s", key); 228 } 229} 230 231static void 232apply_index_property(key, value, idx) 233 char *key; 234 char *value; 235 DB_INDEX *idx; 236{ 237 if (strcasecmp(key, "DBTYPE") == 0) { 238 set_idx_dbtype(idx, value); 239 } else { 240 hc_warn("Unrecognized index property %s", key); 241 } 242} 243 244/* 245 * Apply a configuration keyword and parameter. 246 */ 247 248static void 249apply_configuration_property(key, value) 250 char * key; 251 char *value; 252{ 253 switch (the_parse_progress.last_event) { 254 case PE_NONE: 255 hc_warn( 256 "Property setting (%s) with no antecedent SQL statement", 257 key); 258 break; 259 case PE_ENVIRONMENT: 260 apply_environment_property(key, value); 261 break; 262 case PE_ENTITY: 263 case PE_ATTRIBUTE: /* no per-attribute properties yet */ 264 apply_entity_property(key, value, 265 the_parse_progress.last_entity); 266 break; 267 case PE_INDEX: 268 apply_index_property(key, value, the_parse_progress.last_index); 269 } 270} 271 272/* 273 * Extract property assignments from a SQL comment, if it is marked 274 * as a hint comment. 275 */ 276void parse_hint_comment(t) 277 Token *t; 278{ 279 char *assignment, *key, *value; 280 char *comment; 281 282 comment = hint_comment_from_token(t); 283 284 if (comment == NULL) 285 return; 286 287 while (! (comment == NULL || *comment == '\0')) { 288 assignment = split(comment, ',', &comment); 289 290 /* 291 * Split the assignment into key, value tokens on the 292 * equals sign. Verify that there is only one equals 293 * sign. 294 */ 295 key = split(assignment, '=', &value); 296 297 if (value == NULL) { 298 hc_warn("No value specified for property %s\n", 299 key); 300 break; 301 } 302 303 apply_configuration_property(key, value); 304 305 key = split(key, '=', &value); 306 if (value != NULL) 307 hc_warn( 308 "Warning: incorrect hint comment syntax with property %s", 309 key); 310 } 311} 312