/* {{{ proto int ora_fetch(int cursor) Fetch a row of result data from a cursor */ void php3_Ora_Fetch(INTERNAL_FUNCTION_PARAMETERS) { /* cursor_index */ pval *arg; oraCursor *cursor; if (getParameters(ht, 1, &arg) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long(arg); /* Find the cursor */ if ((cursor = ora_get_cursor(list, arg->value.lval)) == NULL) { RETURN_FALSE; } if (cursor->ncols == 0){ php3_error(E_WARNING, "No tuples available on this cursor"); RETURN_FALSE; } /* Get data from Oracle */ if (ofetch(&cursor->cda)) { if (cursor->cda.rc != NO_DATA_FOUND) { php3_error(E_WARNING, "Ora_Fetch failed (%s)", ora_error(&cursor->cda)); } RETURN_FALSE; } cursor->fetched++; RETVAL_TRUE; }
static int perform_oracle_search(uschar *query, uschar *server, uschar **resultptr, uschar **errmsg, BOOL *defer_break) { Cda_Def *cda = NULL; struct cda_def *oracle_handle = NULL; Ora_Describe *desc = NULL; Ora_Define *def = NULL; void *hda = NULL; int i; int ssize = 0; int offset = 0; int yield = DEFER; unsigned int num_fields = 0; uschar *result = NULL; oracle_connection *cn = NULL; uschar *server_copy = NULL; uschar *sdata[4]; uschar tmp[1024]; /* Disaggregate the parameters from the server argument. The order is host, database, user, password. We can write to the string, since it is in a nextinlist temporary buffer. The copy of the string that is used for caching has the password removed. This copy is also used for debugging output. */ for (i = 3; i > 0; i--) { uschar *pp = Ustrrchr(server, '/'); if (pp == NULL) { *errmsg = string_sprintf("incomplete ORACLE server data: %s", server); *defer_break = TRUE; return DEFER; } *pp++ = 0; sdata[i] = pp; if (i == 3) server_copy = string_copy(server); /* sans password */ } sdata[0] = server; /* What's left at the start */ /* If the database is the empty string, set it NULL - the query must then define it. */ if (sdata[1][0] == 0) sdata[1] = NULL; /* See if we have a cached connection to the server */ for (cn = oracle_connections; cn != NULL; cn = cn->next) { if (strcmp(cn->server, server_copy) == 0) { oracle_handle = cn->handle; hda = cn->hda_mem; break; } } /* If no cached connection, we must set one up */ if (cn == NULL) { DEBUG(D_lookup) debug_printf("ORACLE new connection: host=%s database=%s " "user=%s\n", sdata[0], sdata[1], sdata[2]); /* Get store for a new connection, initialize it, and connect to the server */ oracle_handle = store_get(sizeof(struct cda_def)); hda = store_get(HDA_SIZE); memset(hda,'\0',HDA_SIZE); /* * Perform a default (blocking) login * * sdata[0] = tnsname (service name - typically host name) * sdata[1] = dbname - not used at present * sdata[2] = username * sdata[3] = passwd */ if(olog(oracle_handle, hda, sdata[2], -1, sdata[3], -1, sdata[0], -1, (ub4)OCI_LM_DEF) != 0) { *errmsg = oracle_error(oracle_handle, oracle_handle->rc, US"connection failed"); *defer_break = FALSE; goto ORACLE_EXIT_NO_VALS; } /* Add the connection to the cache */ cn = store_get(sizeof(oracle_connection)); cn->server = server_copy; cn->handle = oracle_handle; cn->next = oracle_connections; cn->hda_mem = hda; oracle_connections = cn; } /* Else use a previously cached connection - we can write to the server string to obliterate the password because it is in a nextinlist temporary buffer. */ else { DEBUG(D_lookup) debug_printf("ORACLE using cached connection for %s\n", server_copy); } /* We have a connection. Open a cursor and run the query */ cda = store_get(sizeof(Cda_Def)); if (oopen(cda, oracle_handle, (text *)0, -1, -1, (text *)0, -1) != 0) { *errmsg = oracle_error(oracle_handle, cda->rc, "failed to open cursor"); *defer_break = FALSE; goto ORACLE_EXIT_NO_VALS; } if (oparse(cda, (text *)query, (sb4) -1, (sword)PARSE_NO_DEFER, (ub4)PARSE_V7_LNG) != 0) { *errmsg = oracle_error(oracle_handle, cda->rc, "query failed"); *defer_break = FALSE; oclose(cda); goto ORACLE_EXIT_NO_VALS; } /* Find the number of fields returned and sort out their types. If the number is one, we don't add field names to the data. Otherwise we do. */ def = store_get(sizeof(Ora_Define)*MAX_SELECT_LIST_SIZE); desc = store_get(sizeof(Ora_Describe)*MAX_SELECT_LIST_SIZE); if ((num_fields = describe_define(cda,def,desc)) == -1) { *errmsg = oracle_error(oracle_handle, cda->rc, "describe_define failed"); *defer_break = FALSE; goto ORACLE_EXIT; } if (oexec(cda)!=0) { *errmsg = oracle_error(oracle_handle, cda->rc, "oexec failed"); *defer_break = FALSE; goto ORACLE_EXIT; } /* Get the fields and construct the result string. If there is more than one row, we insert '\n' between them. */ while (cda->rc != NO_DATA_FOUND) /* Loop for each row */ { ofetch(cda); if(cda->rc == NO_DATA_FOUND) break; if (result != NULL) result = string_cat(result, &ssize, &offset, "\n", 1); /* Single field - just add on the data */ if (num_fields == 1) result = string_cat(result, &ssize, &offset, def[0].buf, def[0].col_retlen); /* Multiple fields - precede by file name, removing {lead,trail}ing WS */ else for (i = 0; i < num_fields; i++) { int slen; uschar *s = US desc[i].buf; while (*s != 0 && isspace(*s)) s++; slen = Ustrlen(s); while (slen > 0 && isspace(s[slen-1])) slen--; result = string_cat(result, &ssize, &offset, s, slen); result = string_cat(result, &ssize, &offset, US"=", 1); /* int and float type wont ever need escaping. Otherwise, quote the value if it contains spaces or is empty. */ if (desc[i].dbtype != INT_TYPE && desc[i].dbtype != FLOAT_TYPE && (def[i].buf[0] == 0 || strchr(def[i].buf, ' ') != NULL)) { int j; result = string_cat(result, &ssize, &offset, "\"", 1); for (j = 0; j < def[i].col_retlen; j++) { if (def[i].buf[j] == '\"' || def[i].buf[j] == '\\') result = string_cat(result, &ssize, &offset, "\\", 1); result = string_cat(result, &ssize, &offset, def[i].buf+j, 1); } result = string_cat(result, &ssize, &offset, "\"", 1); } else switch(desc[i].dbtype) { case INT_TYPE: sprintf(CS tmp, "%d", def[i].int_buf); result = string_cat(result, &ssize, &offset, tmp, Ustrlen(tmp)); break; case FLOAT_TYPE: sprintf(CS tmp, "%f", def[i].flt_buf); result = string_cat(result, &ssize, &offset, tmp, Ustrlen(tmp)); break; case STRING_TYPE: result = string_cat(result, &ssize, &offset, def[i].buf, def[i].col_retlen); break; default: *errmsg = string_sprintf("ORACLE: unknown field type %d", desc[i].dbtype); *defer_break = FALSE; result = NULL; goto ORACLE_EXIT; } result = string_cat(result, &ssize, &offset, " ", 1); } } /* If result is NULL then no data has been found and so we return FAIL. Otherwise, we must terminate the string which has been built; string_cat() always leaves enough room for a terminating zero. */ if (result == NULL) { yield = FAIL; *errmsg = "ORACLE: no data found"; } else { result[offset] = 0; store_reset(result + offset + 1); } /* Get here by goto from various error checks. */ ORACLE_EXIT: /* Close the cursor; don't close the connection, as it is cached. */ oclose(cda); ORACLE_EXIT_NO_VALS: /* Non-NULL result indicates a sucessful result */ if (result != NULL) { *resultptr = result; return OK; } else { DEBUG(D_lookup) debug_printf("%s\n", *errmsg); return yield; /* FAIL or DEFER */ } }
/* {{{ proto mixed ora_getcolumn(int cursor, int column) Get data from a fetched row */ void php3_Ora_GetColumn(INTERNAL_FUNCTION_PARAMETERS) { /* cursor_index, column_index */ pval *argv[2]; int colno; oraCursor *cursor = NULL; oraColumn *column = NULL; sb2 type; if (ARG_COUNT(ht) != 2 || getParametersArray(ht, 2, argv) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long(argv[0]); /* Find the cursor */ if ((cursor = ora_get_cursor(list, argv[0]->value.lval)) == NULL) { RETURN_FALSE; } if (cursor->ncols == 0){ php3_error(E_WARNING, "No tuples available at this cursor index"); RETURN_FALSE; } convert_to_long(argv[1]); colno = argv[1]->value.lval; if (colno >= cursor->ncols){ php3_error(E_WARNING, "Column index larger than number of columns"); RETURN_FALSE; } if (colno < 0){ php3_error(E_WARNING, "Column numbering starts at 0"); RETURN_FALSE; } if (cursor->fetched == 0){ if (ofetch(&cursor->cda)) { if (cursor->cda.rc != NO_DATA_FOUND) { php3_error(E_WARNING, "Ora_Fetch failed (%s)", ora_error(&cursor->cda)); } RETURN_FALSE; } cursor->fetched++; } column = &cursor->columns[colno]; type = column->dbtype; if (column->col_retcode != 0 && column->col_retcode != 1406) { /* So error fetching column. The most common is 1405, a NULL * was retreived. 1406 is ASCII or string buffer data was * truncated. The converted data from the database did not fit * into the buffer. Since we allocated the buffer to be large * enough, this should not occur. Anyway, we probably want to * return what we did get, in that case */ RETURN_FALSE; } else { switch(type) { case SQLT_CHR: case SQLT_NUM: case SQLT_INT: case SQLT_FLT: case SQLT_STR: case SQLT_UIN: case SQLT_AFC: case SQLT_AVC: case SQLT_DAT: RETURN_STRINGL(column->buf, min(column->col_retlen, column->dsize), 1); case SQLT_LNG: case SQLT_LBI: #if 0 { ub4 ret_len; /* XXX 64k max for LONG and LONG RAW */ oflng(&cursor->cda, (sword)(colno + 1), column->buf, DB_SIZE, 1, &ret_len, 0); RETURN_STRINGL(column->buf, ret_len, 1); } #else { ub4 ret_len; int offset = column->col_retlen; sb2 result; if (column->col_retcode == 1406) { /* truncation -> get the rest! */ while (1) { column->buf = erealloc(column->buf,offset + DB_SIZE + 1); if (! column->buf) { offset = 0; break; } result = oflng(&cursor->cda, (sword)(colno + 1), column->buf + offset, DB_SIZE, 1, &ret_len, offset); if (result) { break; } if (ret_len <= 0) { break; } offset += ret_len; } } if (column->buf && offset) { RETURN_STRINGL(column->buf, offset, 1); } else { RETURN_FALSE; } } #endif default: php3_error(E_WARNING, "Ora_GetColumn found invalid type (%d)", type); RETURN_FALSE; } } }
/* {{{ proto int ora_fetch_into(int cursor, array result [, int flags]) Fetch a row into the specified result array */ void php3_Ora_FetchInto(INTERNAL_FUNCTION_PARAMETERS) { pval *arg1, *arr, *flg, *tmp; oraCursor *cursor; int i; int flags = 0; switch(ARG_COUNT(ht)){ case 2: if (getParameters(ht, 2, &arg1, &arr) == FAILURE) { WRONG_PARAM_COUNT; } break; case 3: if (getParameters(ht, 3, &arg1, &arr, &flg) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long(flg); flags = flg->value.lval; break; default: WRONG_PARAM_COUNT; break; } if (!ParameterPassedByReference(ht, 2)){ php3_error(E_WARNING, "Array not passed by reference in call to ora_fetch_into()"); RETURN_FALSE; } convert_to_long(arg1); /* Find the cursor */ if ((cursor = ora_get_cursor(list, arg1->value.lval)) == NULL) { RETURN_FALSE; } if (cursor->ncols == 0){ php3_error(E_WARNING, "No tuples available on this cursor"); RETURN_FALSE; } if (ofetch(&cursor->cda)) { if (cursor->cda.rc != NO_DATA_FOUND) { php3_error(E_WARNING, "Ora_Fetch_Into failed (%s)", ora_error(&cursor->cda)); } RETURN_FALSE; } cursor->fetched++; if (arr->type != IS_ARRAY){ php3tls_pval_destructor(arr); if (array_init(arr) == FAILURE){ php3_error(E_WARNING, "Can't convert to type Array"); RETURN_FALSE; } } _php3_hash_internal_pointer_reset(arr->value.ht); #if PHP_API_VERSION < 19990421 tmp = emalloc(sizeof(pval)); #endif for (i = 0; i < cursor->ncols; i++) { if (cursor->columns[i].col_retcode == 1405) { if (!(flags&ORA_FETCHINTO_NULLS)){ continue; /* don't add anything for NULL columns, unless the calles wants it */ } else { tmp->value.str.val = empty_string; tmp->value.str.len = 0; } } else if (cursor->columns[i].col_retcode != 0 && cursor->columns[i].col_retcode != 1406) { /* So error fetching column. The most common is 1405, a NULL */ /* was retreived. 1406 is ASCII or string buffer data was */ /* truncated. The converted data from the database did not fit */ /* into the buffer. Since we allocated the buffer to be large */ /* enough, this should not occur. Anyway, we probably want to */ /* return what we did get, in that case */ RETURN_FALSE; } else { #if PHP_API_VERSION >= 19990421 MAKE_STD_ZVAL(tmp); #endif tmp->type = IS_STRING; tmp->value.str.len = 0; switch(cursor->columns[i].dbtype) { case SQLT_LNG: case SQLT_LBI: { ub4 ret_len; int offset = cursor->columns[i].col_retlen; sb2 result; if (cursor->columns[i].col_retcode == 1406) { /* truncation -> get the rest! */ while (1) { cursor->columns[i].buf = erealloc(cursor->columns[i].buf,offset + DB_SIZE + 1); if (! cursor->columns[i].buf) { offset = 0; break; } result = oflng(&cursor->cda, (sword)(i + 1), cursor->columns[i].buf + offset, DB_SIZE, 1, &ret_len, offset); if (result) { break; } if (ret_len <= 0) { break; } offset += ret_len; } } if (cursor->columns[i].buf && offset) { tmp->value.str.len = offset; } else { tmp->value.str.len = 0; } } break; default: tmp->value.str.len = min(cursor->columns[i].col_retlen, cursor->columns[i].dsize); break; } tmp->value.str.val = estrndup(cursor->columns[i].buf,tmp->value.str.len); } if (flags&ORA_FETCHINTO_ASSOC){ #if PHP_API_VERSION >= 19990421 _php3_hash_update(arr->value.ht, cursor->columns[i].cbuf, cursor->columns[i].cbufl+1, (void *) &tmp, sizeof(pval*), NULL); #else _php3_hash_update(arr->value.ht, cursor->columns[i].cbuf, cursor->columns[i].cbufl+1, (void *) tmp, sizeof(pval), NULL); #endif } else { #if PHP_API_VERSION >= 19990421 _php3_hash_index_update(arr->value.ht, i, (void *) &tmp, sizeof(pval*), NULL); #else _php3_hash_index_update(arr->value.ht, i, (void *) tmp, sizeof(pval), NULL); #endif } } #if PHP_API_VERSION < 19990421 efree(tmp); #endif RETURN_LONG(cursor->ncols); }